mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Added voice input for caption and description (#5415)
* Fixed Grey empty screen at Upload wizard caption step after denying files permission * Empty commit * Fixed loop issue * Created docs for earlier commits * Fixed javadoc * Fixed spaces * Added added basic features to OSM Maps * Added search location feature * Added filter to Open Street Maps * Fixed chipGroup in Open Street Maps * Removed mapBox code * Removed mapBox's code * Reformat code * Reformatted code * Removed rotation feature to map * Removed rotation files and Fixed Marker click problem * Ignored failing tests * Added voice input feature * Fixed test cases * Changed caption and description text
This commit is contained in:
parent
e5c789e874
commit
b7090d90c4
9 changed files with 296 additions and 108 deletions
|
|
@ -1,9 +1,11 @@
|
||||||
package fr.free.nrw.commons.description
|
package fr.free.nrw.commons.description
|
||||||
|
|
||||||
|
import android.app.Activity.RESULT_OK
|
||||||
import android.app.ProgressDialog
|
import android.app.ProgressDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import android.speech.RecognizerIntent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
@ -18,6 +20,7 @@ import fr.free.nrw.commons.theme.BaseActivity
|
||||||
import fr.free.nrw.commons.upload.UploadMediaDetail
|
import fr.free.nrw.commons.upload.UploadMediaDetail
|
||||||
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter
|
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter
|
||||||
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
|
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,6 +58,8 @@ class DescriptionEditActivity : BaseActivity(), UploadMediaDetailAdapter.EventLi
|
||||||
|
|
||||||
private lateinit var binding: ActivityDescriptionEditBinding
|
private lateinit var binding: ActivityDescriptionEditBinding
|
||||||
|
|
||||||
|
private val REQUEST_CODE_FOR_VOICE_INPUT = 1213
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
|
@ -78,7 +83,7 @@ class DescriptionEditActivity : BaseActivity(), UploadMediaDetailAdapter.EventLi
|
||||||
* @param descriptionAndCaptions list of description and caption
|
* @param descriptionAndCaptions list of description and caption
|
||||||
*/
|
*/
|
||||||
private fun initRecyclerView(descriptionAndCaptions: ArrayList<UploadMediaDetail>?) {
|
private fun initRecyclerView(descriptionAndCaptions: ArrayList<UploadMediaDetail>?) {
|
||||||
uploadMediaDetailAdapter = UploadMediaDetailAdapter(
|
uploadMediaDetailAdapter = UploadMediaDetailAdapter(this,
|
||||||
savedLanguageValue, descriptionAndCaptions, recentLanguagesDao)
|
savedLanguageValue, descriptionAndCaptions, recentLanguagesDao)
|
||||||
uploadMediaDetailAdapter.setCallback { titleStringID: Int, messageStringId: Int ->
|
uploadMediaDetailAdapter.setCallback { titleStringID: Int, messageStringId: Int ->
|
||||||
showInfoAlert(
|
showInfoAlert(
|
||||||
|
|
@ -175,4 +180,15 @@ class DescriptionEditActivity : BaseActivity(), UploadMediaDetailAdapter.EventLi
|
||||||
progressDialog!!.setCanceledOnTouchOutside(false)
|
progressDialog!!.setCanceledOnTouchOutside(false)
|
||||||
progressDialog!!.show()
|
progressDialog!!.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override
|
||||||
|
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
if (requestCode == REQUEST_CODE_FOR_VOICE_INPUT) {
|
||||||
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
|
val result = data.getStringArrayListExtra( RecognizerIntent.EXTRA_RESULTS )
|
||||||
|
uploadMediaDetailAdapter.handleSpeechResult(result!![0]) }
|
||||||
|
else { Timber.e("Error %s", resultCode) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package fr.free.nrw.commons.upload;
|
package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.speech.RecognizerIntent;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputFilter;
|
import android.text.InputFilter;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
@ -13,10 +16,12 @@ import android.widget.AdapterView;
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
@ -30,11 +35,13 @@ import fr.free.nrw.commons.utils.AbstractTextWatcher;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDetailAdapter.ViewHolder> {
|
public class UploadMediaDetailAdapter extends
|
||||||
|
RecyclerView.Adapter<UploadMediaDetailAdapter.ViewHolder> {
|
||||||
|
|
||||||
RecentLanguagesDao recentLanguagesDao;
|
RecentLanguagesDao recentLanguagesDao;
|
||||||
|
|
||||||
|
|
@ -47,20 +54,28 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
private TextView recentLanguagesTextView;
|
private TextView recentLanguagesTextView;
|
||||||
private View separator;
|
private View separator;
|
||||||
private ListView languageHistoryListView;
|
private ListView languageHistoryListView;
|
||||||
|
private int currentPosition;
|
||||||
|
private Fragment fragment;
|
||||||
|
private Activity activity;
|
||||||
|
private SelectedVoiceIcon selectedVoiceIcon;
|
||||||
|
private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213;
|
||||||
|
|
||||||
public UploadMediaDetailAdapter(String savedLanguageValue, RecentLanguagesDao recentLanguagesDao) {
|
public UploadMediaDetailAdapter(Fragment fragment, String savedLanguageValue,
|
||||||
|
RecentLanguagesDao recentLanguagesDao) {
|
||||||
uploadMediaDetails = new ArrayList<>();
|
uploadMediaDetails = new ArrayList<>();
|
||||||
selectedLanguages = new HashMap<>();
|
selectedLanguages = new HashMap<>();
|
||||||
this.savedLanguageValue = savedLanguageValue;
|
this.savedLanguageValue = savedLanguageValue;
|
||||||
this.recentLanguagesDao = recentLanguagesDao;
|
this.recentLanguagesDao = recentLanguagesDao;
|
||||||
|
this.fragment = fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UploadMediaDetailAdapter(final String savedLanguageValue,
|
public UploadMediaDetailAdapter(Activity activity, final String savedLanguageValue,
|
||||||
List<UploadMediaDetail> uploadMediaDetails, RecentLanguagesDao recentLanguagesDao) {
|
List<UploadMediaDetail> uploadMediaDetails, RecentLanguagesDao recentLanguagesDao) {
|
||||||
this.uploadMediaDetails = uploadMediaDetails;
|
this.uploadMediaDetails = uploadMediaDetails;
|
||||||
selectedLanguages = new HashMap<>();
|
selectedLanguages = new HashMap<>();
|
||||||
this.savedLanguageValue = savedLanguageValue;
|
this.savedLanguageValue = savedLanguageValue;
|
||||||
this.recentLanguagesDao = recentLanguagesDao;
|
this.recentLanguagesDao = recentLanguagesDao;
|
||||||
|
this.activity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCallback(Callback callback) {
|
public void setCallback(Callback callback) {
|
||||||
|
|
@ -77,7 +92,7 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UploadMediaDetail> getItems(){
|
public List<UploadMediaDetail> getItems() {
|
||||||
return uploadMediaDetails;
|
return uploadMediaDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,13 +100,14 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
return new ViewHolder(LayoutInflater.from(parent.getContext())
|
return new ViewHolder(LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.row_item_description, parent, false));
|
.inflate(R.layout.row_item_description, parent, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a workaround for a known bug by android here https://issuetracker.google.com/issues/37095917
|
* This is a workaround for a known bug by android here
|
||||||
* makes the edit text on second and subsequent fragments inside an adapter receptive to long click
|
* https://issuetracker.google.com/issues/37095917 makes the edit text on second and subsequent
|
||||||
* for copy/paste options
|
* fragments inside an adapter receptive to long click for copy/paste options
|
||||||
|
*
|
||||||
* @param holder the view holder
|
* @param holder the view holder
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -119,9 +135,43 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
notifyItemInserted(uploadMediaDetails.size());
|
notifyItemInserted(uploadMediaDetails.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startSpeechInput(String locale) {
|
||||||
|
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
|
||||||
|
intent.putExtra(
|
||||||
|
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
|
||||||
|
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
|
||||||
|
);
|
||||||
|
intent.putExtra(
|
||||||
|
RecognizerIntent.EXTRA_LANGUAGE,
|
||||||
|
locale
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
if (activity == null){
|
||||||
|
fragment.startActivityForResult(intent, REQUEST_CODE_FOR_VOICE_INPUT);
|
||||||
|
}else {
|
||||||
|
activity.startActivityForResult(intent, REQUEST_CODE_FOR_VOICE_INPUT);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Timber.e(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleSpeechResult(String spokenText) {
|
||||||
|
if (currentPosition < uploadMediaDetails.size()) {
|
||||||
|
UploadMediaDetail uploadMediaDetail = uploadMediaDetails.get(currentPosition);
|
||||||
|
if (selectedVoiceIcon == SelectedVoiceIcon.CAPTION){
|
||||||
|
uploadMediaDetail.setCaptionText(spokenText);
|
||||||
|
}else {
|
||||||
|
uploadMediaDetail.setDescriptionText(spokenText);
|
||||||
|
}
|
||||||
|
notifyItemChanged(currentPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove description based on position from the list and notifies the RecyclerView Adapter that
|
* Remove description based on position from the list and notifies the RecyclerView Adapter that
|
||||||
* data in adapter has been removed at that particular position.
|
* data in adapter has been removed at that particular position.
|
||||||
|
*
|
||||||
* @param uploadMediaDetail
|
* @param uploadMediaDetail
|
||||||
* @param position
|
* @param position
|
||||||
*/
|
*/
|
||||||
|
|
@ -160,6 +210,12 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
@BindView(R.id.btn_remove)
|
@BindView(R.id.btn_remove)
|
||||||
ImageView removeButton;
|
ImageView removeButton;
|
||||||
|
|
||||||
|
@BindView(R.id.ll_write_better_caption)
|
||||||
|
LinearLayout betterCaptionLinearLayout;
|
||||||
|
|
||||||
|
@BindView(R.id.ll_write_better_description)
|
||||||
|
LinearLayout betterDescriptionLinearLayout;
|
||||||
|
|
||||||
AbstractTextWatcher captionListener;
|
AbstractTextWatcher captionListener;
|
||||||
|
|
||||||
AbstractTextWatcher descriptionListener;
|
AbstractTextWatcher descriptionListener;
|
||||||
|
|
@ -185,34 +241,48 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
descItemEditText.removeTextChangedListener(descriptionListener);
|
descItemEditText.removeTextChangedListener(descriptionListener);
|
||||||
captionItemEditText.setText(uploadMediaDetail.getCaptionText());
|
captionItemEditText.setText(uploadMediaDetail.getCaptionText());
|
||||||
descItemEditText.setText(uploadMediaDetail.getDescriptionText());
|
descItemEditText.setText(uploadMediaDetail.getDescriptionText());
|
||||||
|
captionInputLayout.setEndIconMode(TextInputLayout.END_ICON_CUSTOM);
|
||||||
|
captionInputLayout.setEndIconDrawable(R.drawable.baseline_keyboard_voice);
|
||||||
|
captionInputLayout.setEndIconOnClickListener(v -> {
|
||||||
|
currentPosition = position;
|
||||||
|
selectedVoiceIcon = SelectedVoiceIcon.CAPTION;
|
||||||
|
startSpeechInput(descriptionLanguages.getText().toString());
|
||||||
|
});
|
||||||
|
descInputLayout.setEndIconMode(TextInputLayout.END_ICON_CUSTOM);
|
||||||
|
descInputLayout.setEndIconDrawable(R.drawable.baseline_keyboard_voice);
|
||||||
|
descInputLayout.setEndIconOnClickListener(v -> {
|
||||||
|
currentPosition = position;
|
||||||
|
selectedVoiceIcon = SelectedVoiceIcon.DESCRIPTION;
|
||||||
|
startSpeechInput(descriptionLanguages.getText().toString());
|
||||||
|
});
|
||||||
|
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
removeButton.setVisibility(View.GONE);
|
removeButton.setVisibility(View.GONE);
|
||||||
captionInputLayout.setEndIconMode(TextInputLayout.END_ICON_CUSTOM);
|
betterCaptionLinearLayout.setVisibility(View.VISIBLE);
|
||||||
captionInputLayout.setEndIconDrawable(R.drawable.maplibre_info_icon_default);
|
betterCaptionLinearLayout.setOnClickListener(
|
||||||
captionInputLayout.setEndIconOnClickListener(v ->
|
v -> callback.showAlert(R.string.media_detail_caption, R.string.caption_info));
|
||||||
callback.showAlert(R.string.media_detail_caption, R.string.caption_info));
|
betterDescriptionLinearLayout.setVisibility(View.VISIBLE);
|
||||||
Objects.requireNonNull(captionInputLayout.getEditText()).setFilters(new InputFilter[] {
|
betterDescriptionLinearLayout.setOnClickListener(
|
||||||
new UploadMediaDetailInputFilter()
|
v -> callback.showAlert(R.string.media_detail_description,
|
||||||
});
|
R.string.description_info));
|
||||||
|
Objects.requireNonNull(captionInputLayout.getEditText())
|
||||||
descInputLayout.setEndIconMode(TextInputLayout.END_ICON_CUSTOM);
|
.setFilters(new InputFilter[]{
|
||||||
descInputLayout.setEndIconDrawable(R.drawable.maplibre_info_icon_default);
|
new UploadMediaDetailInputFilter()
|
||||||
descInputLayout.setEndIconOnClickListener(v ->
|
});
|
||||||
callback.showAlert(R.string.media_detail_description, R.string.description_info));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
removeButton.setVisibility(View.VISIBLE);
|
removeButton.setVisibility(View.VISIBLE);
|
||||||
captionInputLayout.setEndIconDrawable(null);
|
betterCaptionLinearLayout.setVisibility(View.GONE);
|
||||||
descInputLayout.setEndIconDrawable(null);
|
betterDescriptionLinearLayout.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeButton.setOnClickListener(v -> removeDescription(uploadMediaDetail, position));
|
removeButton.setOnClickListener(v -> removeDescription(uploadMediaDetail, position));
|
||||||
captionListener = new AbstractTextWatcher(
|
captionListener = new AbstractTextWatcher(
|
||||||
captionText -> uploadMediaDetails.get(position).setCaptionText(convertIdeographicSpaceToLatinSpace(
|
captionText -> uploadMediaDetails.get(position)
|
||||||
removeLeadingAndTrailingWhitespace(captionText))));
|
.setCaptionText(convertIdeographicSpaceToLatinSpace(
|
||||||
|
removeLeadingAndTrailingWhitespace(captionText))));
|
||||||
descriptionListener = new AbstractTextWatcher(
|
descriptionListener = new AbstractTextWatcher(
|
||||||
descriptionText -> uploadMediaDetails.get(position).setDescriptionText(descriptionText));
|
descriptionText -> uploadMediaDetails.get(position)
|
||||||
|
.setDescriptionText(descriptionText));
|
||||||
captionItemEditText.addTextChangedListener(captionListener);
|
captionItemEditText.addTextChangedListener(captionListener);
|
||||||
initLanguage(position, uploadMediaDetail);
|
initLanguage(position, uploadMediaDetail);
|
||||||
|
|
||||||
|
|
@ -228,23 +298,26 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initLanguage(int position, UploadMediaDetail description) {
|
private void initLanguage(int position, UploadMediaDetail description) {
|
||||||
|
|
||||||
final List<Language> recentLanguages = recentLanguagesDao.getRecentLanguages();
|
final List<Language> recentLanguages = recentLanguagesDao.getRecentLanguages();
|
||||||
|
|
||||||
LanguagesAdapter languagesAdapter = new LanguagesAdapter(
|
LanguagesAdapter languagesAdapter = new LanguagesAdapter(
|
||||||
descriptionLanguages.getContext(),
|
descriptionLanguages.getContext(),
|
||||||
selectedLanguages
|
selectedLanguages
|
||||||
);
|
);
|
||||||
|
|
||||||
descriptionLanguages.setOnClickListener(new OnClickListener() {
|
descriptionLanguages.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
Dialog dialog = new Dialog(view.getContext());
|
Dialog dialog = new Dialog(view.getContext());
|
||||||
dialog.setContentView(R.layout.dialog_select_language);
|
dialog.setContentView(R.layout.dialog_select_language);
|
||||||
dialog.setCanceledOnTouchOutside(true);
|
dialog.setCanceledOnTouchOutside(true);
|
||||||
dialog.getWindow().setLayout((int)(view.getContext().getResources().getDisplayMetrics().widthPixels*0.90),
|
dialog.getWindow().setLayout(
|
||||||
(int)(view.getContext().getResources().getDisplayMetrics().heightPixels*0.90));
|
(int) (view.getContext().getResources().getDisplayMetrics().widthPixels
|
||||||
|
* 0.90),
|
||||||
|
(int) (view.getContext().getResources().getDisplayMetrics().heightPixels
|
||||||
|
* 0.90));
|
||||||
dialog.show();
|
dialog.show();
|
||||||
|
|
||||||
EditText editText = dialog.findViewById(R.id.search_language);
|
EditText editText = dialog.findViewById(R.id.search_language);
|
||||||
|
|
@ -275,9 +348,10 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
languageHistoryListView.setOnItemClickListener((adapterView, view1, position, id) -> {
|
languageHistoryListView.setOnItemClickListener(
|
||||||
onRecentLanguageClicked(dialog, adapterView, position, description);
|
(adapterView, view1, position, id) -> {
|
||||||
});
|
onRecentLanguageClicked(dialog, adapterView, position, description);
|
||||||
|
});
|
||||||
|
|
||||||
listView.setOnItemClickListener(new OnItemClickListener() {
|
listView.setOnItemClickListener(new OnItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -317,7 +391,7 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
if (!TextUtils.isEmpty(savedLanguageValue)) {
|
if (!TextUtils.isEmpty(savedLanguageValue)) {
|
||||||
// If user has chosen a default language from settings activity
|
// If user has chosen a default language from settings activity
|
||||||
// savedLanguageValue is not null
|
// savedLanguageValue is not null
|
||||||
if(!TextUtils.isEmpty(description.getLanguageCode())) {
|
if (!TextUtils.isEmpty(description.getLanguageCode())) {
|
||||||
descriptionLanguages.setText(description.getLanguageCode());
|
descriptionLanguages.setText(description.getLanguageCode());
|
||||||
selectedLanguages.remove(position);
|
selectedLanguages.remove(position);
|
||||||
selectedLanguages.put(position, description.getLanguageCode());
|
selectedLanguages.put(position, description.getLanguageCode());
|
||||||
|
|
@ -349,9 +423,11 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
.getContext());
|
.getContext());
|
||||||
descriptionLanguages
|
descriptionLanguages
|
||||||
.setText(languagesAdapter.getLanguageCode(defaultLocaleIndex));
|
.setText(languagesAdapter.getLanguageCode(defaultLocaleIndex));
|
||||||
description.setLanguageCode(languagesAdapter.getLanguageCode(defaultLocaleIndex));
|
description.setLanguageCode(
|
||||||
|
languagesAdapter.getLanguageCode(defaultLocaleIndex));
|
||||||
selectedLanguages.remove(position);
|
selectedLanguages.remove(position);
|
||||||
selectedLanguages.put(position, languagesAdapter.getLanguageCode(defaultLocaleIndex));
|
selectedLanguages.put(position,
|
||||||
|
languagesAdapter.getLanguageCode(defaultLocaleIndex));
|
||||||
} else {
|
} else {
|
||||||
description.setLanguageCode(languagesAdapter.getLanguageCode(0));
|
description.setLanguageCode(languagesAdapter.getLanguageCode(0));
|
||||||
descriptionLanguages.setText(languagesAdapter.getLanguageCode(0));
|
descriptionLanguages.setText(languagesAdapter.getLanguageCode(0));
|
||||||
|
|
@ -415,7 +491,7 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
separator.setVisibility(View.GONE);
|
separator.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
if (recentLanguages.size() > 5) {
|
if (recentLanguages.size() > 5) {
|
||||||
for (int i = recentLanguages.size()-1; i >=5; i--) {
|
for (int i = recentLanguages.size() - 1; i >= 5; i--) {
|
||||||
recentLanguagesDao.deleteRecentLanguage(recentLanguages.get(i)
|
recentLanguagesDao.deleteRecentLanguage(recentLanguages.get(i)
|
||||||
.getLanguageCode());
|
.getLanguageCode());
|
||||||
}
|
}
|
||||||
|
|
@ -425,15 +501,16 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
separator.setVisibility(View.VISIBLE);
|
separator.setVisibility(View.VISIBLE);
|
||||||
final RecentLanguagesAdapter recentLanguagesAdapter
|
final RecentLanguagesAdapter recentLanguagesAdapter
|
||||||
= new RecentLanguagesAdapter(
|
= new RecentLanguagesAdapter(
|
||||||
descriptionLanguages.getContext(),
|
descriptionLanguages.getContext(),
|
||||||
recentLanguagesDao.getRecentLanguages(),
|
recentLanguagesDao.getRecentLanguages(),
|
||||||
selectedLanguages);
|
selectedLanguages);
|
||||||
languageHistoryListView.setAdapter(recentLanguagesAdapter);
|
languageHistoryListView.setAdapter(recentLanguagesAdapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any leading and trailing whitespace from the source text.
|
* Removes any leading and trailing whitespace from the source text.
|
||||||
|
*
|
||||||
* @param source input string
|
* @param source input string
|
||||||
* @return a string without leading and trailing whitespace
|
* @return a string without leading and trailing whitespace
|
||||||
*/
|
*/
|
||||||
|
|
@ -466,6 +543,7 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Ideographic space to Latin space
|
* Convert Ideographic space to Latin space
|
||||||
|
*
|
||||||
* @param source the source text
|
* @param source the source text
|
||||||
* @return a string with Latin spaces instead of Ideographic spaces
|
* @return a string with Latin spaces instead of Ideographic spaces
|
||||||
*/
|
*/
|
||||||
|
|
@ -483,5 +561,8 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
public interface EventListener {
|
public interface EventListener {
|
||||||
void onPrimaryCaptionTextChange(boolean isNotEmpty);
|
void onPrimaryCaptionTextChange(boolean isNotEmpty);
|
||||||
}
|
}
|
||||||
|
enum SelectedVoiceIcon {
|
||||||
|
CAPTION,
|
||||||
|
DESCRIPTION
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,13 @@ import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.getErrorMessageForResult;
|
import static fr.free.nrw.commons.utils.ImageUtils.getErrorMessageForResult;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.speech.RecognizerIntent;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
@ -40,7 +38,6 @@ import fr.free.nrw.commons.contributions.MainActivity;
|
||||||
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.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao;
|
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao;
|
||||||
import fr.free.nrw.commons.settings.Prefs;
|
import fr.free.nrw.commons.settings.Prefs;
|
||||||
|
|
@ -54,8 +51,8 @@ import fr.free.nrw.commons.upload.UploadMediaDetailAdapter;
|
||||||
import fr.free.nrw.commons.utils.DialogUtil;
|
import fr.free.nrw.commons.utils.DialogUtil;
|
||||||
import fr.free.nrw.commons.utils.ImageUtils;
|
import fr.free.nrw.commons.utils.ImageUtils;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
import fr.free.nrw.commons.R.drawable.*;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
@ -69,6 +66,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
|
|
||||||
private static final int REQUEST_CODE = 1211;
|
private static final int REQUEST_CODE = 1211;
|
||||||
private static final int REQUEST_CODE_FOR_EDIT_ACTIVITY = 1212;
|
private static final int REQUEST_CODE_FOR_EDIT_ACTIVITY = 1212;
|
||||||
|
private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key for applicationKvStore. By this key we can retrieve the location of last UploadItem ex.
|
* A key for applicationKvStore. By this key we can retrieve the location of last UploadItem ex.
|
||||||
|
|
@ -238,7 +236,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
* init the description recycler veiw and caption recyclerview
|
* init the description recycler veiw and caption recyclerview
|
||||||
*/
|
*/
|
||||||
private void initRecyclerView() {
|
private void initRecyclerView() {
|
||||||
uploadMediaDetailAdapter = new UploadMediaDetailAdapter(
|
uploadMediaDetailAdapter = new UploadMediaDetailAdapter(this,
|
||||||
defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, ""), recentLanguagesDao);
|
defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, ""), recentLanguagesDao);
|
||||||
uploadMediaDetailAdapter.setCallback(this::showInfoAlert);
|
uploadMediaDetailAdapter.setCallback(this::showInfoAlert);
|
||||||
uploadMediaDetailAdapter.setEventListener(this);
|
uploadMediaDetailAdapter.setEventListener(this);
|
||||||
|
|
@ -558,7 +556,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
public void onActivityResult(final int requestCode, final int resultCode,
|
public void onActivityResult(final int requestCode, final int resultCode,
|
||||||
@Nullable final Intent data) {
|
@Nullable final Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
|
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
|
||||||
|
|
||||||
assert data != null;
|
assert data != null;
|
||||||
|
|
@ -597,6 +594,15 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
Timber.e(e);
|
Timber.e(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (requestCode == REQUEST_CODE_FOR_VOICE_INPUT) {
|
||||||
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
|
ArrayList<String> result = data.getStringArrayListExtra(
|
||||||
|
RecognizerIntent.EXTRA_RESULTS);
|
||||||
|
uploadMediaDetailAdapter.handleSpeechResult(result.get(0));
|
||||||
|
}else {
|
||||||
|
Timber.e("Error %s", resultCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
10
app/src/main/res/drawable/baseline_keyboard_voice.xml
Normal file
10
app/src/main/res/drawable/baseline_keyboard_voice.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="21dp"
|
||||||
|
android:height="21dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF1E8CAB"
|
||||||
|
android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM17.3,12c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12L5,12c0,3.42 2.72,6.23 6,6.72L11,22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z" />
|
||||||
|
</vector>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true"
|
||||||
|
android:drawable="@color/pressed_button_light" />
|
||||||
|
<item android:state_focused="false"
|
||||||
|
android:drawable="@android:color/transparent" />
|
||||||
|
</selector>
|
||||||
10
app/src/main/res/drawable/ic_open.xml
Normal file
10
app/src/main/res/drawable/ic_open.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="20dp"
|
||||||
|
android:height="20dp"
|
||||||
|
android:viewportWidth="20"
|
||||||
|
android:tint="?attr/editTextColor"
|
||||||
|
android:viewportHeight="20">
|
||||||
|
<path
|
||||||
|
android:pathData="M17.778,17.778H2.223V2.222H10V0H2.223C0.989,0 0,1 0,2.222V17.778C0,19 0.989,20 2.223,20H17.778C19,20 20,19 20,17.778V10H17.778V17.778ZM12.223,0V2.222H16.212L5.289,13.144L6.856,14.711L17.778,3.789V7.778H20V0H12.223Z"
|
||||||
|
android:fillColor="#8F000000"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -7,68 +7,118 @@
|
||||||
android:layout_marginVertical="8dp"
|
android:layout_marginVertical="8dp"
|
||||||
app:elevation="6dp">
|
app:elevation="6dp">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginHorizontal="20dp"
|
||||||
|
android:layout_marginVertical="20dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btn_remove"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/remove"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_remove" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description_languages"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:drawableRight="@drawable/ic_baseline_arrow_drop_down_24"
|
||||||
|
android:padding="@dimen/dimen_2"
|
||||||
|
android:textSize="18sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/caption_item_edit_text_input_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="20dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginVertical="20dp">
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/description_languages">
|
||||||
|
|
||||||
<ImageView
|
<fr.free.nrw.commons.ui.PasteSensitiveTextInputEditText
|
||||||
android:id="@+id/btn_remove"
|
android:id="@+id/caption_item_edit_text"
|
||||||
android:layout_width="24dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:contentDescription="@string/remove"
|
android:hint="@string/share_caption_hint"
|
||||||
android:visibility="visible"
|
android:imeOptions="actionNext|flagNoExtractUi"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/caption_item_edit_text_input_layout"
|
android:inputType="text"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:allowFormatting="false" />
|
||||||
app:srcCompat="@drawable/ic_remove" />
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/description_languages"
|
android:id="@+id/ll_write_better_caption"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clickable="true"
|
android:layout_marginStart="2dp"
|
||||||
android:drawableRight="@drawable/ic_baseline_arrow_drop_down_24"
|
android:background="@drawable/clicked_linearlayout_background"
|
||||||
android:padding="@dimen/dimen_2"
|
android:clickable="true"
|
||||||
android:textSize="18sp"
|
android:gravity="center_vertical"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/caption_item_edit_text_input_layout"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintTop_toBottomOf="@+id/caption_item_edit_text_input_layout">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<TextView
|
||||||
android:id="@+id/caption_item_edit_text_input_layout"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:text="@string/learn_how_to_write_a_useful_caption"
|
||||||
app:layout_constraintBottom_toTopOf="@id/description_item_edit_text_input_layout"
|
android:textSize="12sp" />
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
|
||||||
|
|
||||||
<fr.free.nrw.commons.ui.PasteSensitiveTextInputEditText
|
<ImageView
|
||||||
android:id="@+id/caption_item_edit_text"
|
android:layout_width="10dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="10dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_marginStart="6dp"
|
||||||
android:hint="@string/share_caption_hint"
|
app:srcCompat="@drawable/ic_open" />
|
||||||
android:imeOptions="actionNext|flagNoExtractUi"
|
|
||||||
android:inputType="text"
|
|
||||||
app:allowFormatting="false" />
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
</LinearLayout>
|
||||||
android:id="@+id/description_item_edit_text_input_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
|
||||||
|
|
||||||
<fr.free.nrw.commons.ui.PasteSensitiveTextInputEditText
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/description_item_edit_text"
|
android:id="@+id/description_item_edit_text_input_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/share_description_hint"
|
android:layout_marginTop="4dp"
|
||||||
android:imeOptions="actionNext|flagNoExtractUi"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:inputType="textMultiLine"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:allowFormatting="false" />
|
app:layout_constraintTop_toBottomOf="@+id/ll_write_better_caption">
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<fr.free.nrw.commons.ui.PasteSensitiveTextInputEditText
|
||||||
|
android:id="@+id/description_item_edit_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:hint="@string/share_description_hint"
|
||||||
|
android:imeOptions="actionNext|flagNoExtractUi"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
app:allowFormatting="false" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_write_better_description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="2dp"
|
||||||
|
android:background="@drawable/clicked_linearlayout_background"
|
||||||
|
android:clickable="true"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/description_item_edit_text_input_layout">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/learn_how_to_write_a_useful_description"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
app:srcCompat="@drawable/ic_open" />
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
|
||||||
|
|
@ -784,6 +784,8 @@ Upload your first media by tapping on the add button.</string>
|
||||||
<string name="storage_permissions_denied">Storage Permissions Denied</string>
|
<string name="storage_permissions_denied">Storage Permissions Denied</string>
|
||||||
<string name="unable_to_share_upload_item">Unable to share this item</string>
|
<string name="unable_to_share_upload_item">Unable to share this item</string>
|
||||||
<string name="permissions_are_required_for_functionality">Permissions are required for functionality</string>
|
<string name="permissions_are_required_for_functionality">Permissions are required for functionality</string>
|
||||||
|
<string name="learn_how_to_write_a_useful_description">Learn how to write a useful description</string>
|
||||||
|
<string name="learn_how_to_write_a_useful_caption">Learn how to write a useful caption</string>
|
||||||
<plurals name="custom_picker_images_selected_title_appendix">
|
<plurals name="custom_picker_images_selected_title_appendix">
|
||||||
<item quantity="one">%d image selected</item>
|
<item quantity="one">%d image selected</item>
|
||||||
<item quantity="other">%d images selected</item>
|
<item quantity="other">%d images selected</item>
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,14 @@ import fr.free.nrw.commons.recentlanguages.Language
|
||||||
import fr.free.nrw.commons.recentlanguages.RecentLanguagesAdapter
|
import fr.free.nrw.commons.recentlanguages.RecentLanguagesAdapter
|
||||||
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
|
import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao
|
||||||
import fr.free.nrw.commons.settings.SettingsFragment
|
import fr.free.nrw.commons.settings.SettingsFragment
|
||||||
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito
|
import org.mockito.Mockito
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
import org.powermock.reflect.Whitebox
|
import org.powermock.reflect.Whitebox
|
||||||
import org.robolectric.Robolectric
|
import org.robolectric.Robolectric
|
||||||
|
|
@ -55,6 +57,9 @@ class UploadMediaDetailAdapterUnitTest {
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var textView: TextView
|
private lateinit var textView: TextView
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var fragment : UploadMediaDetailFragment
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var view: View
|
private lateinit var view: View
|
||||||
|
|
||||||
|
|
@ -69,7 +74,8 @@ class UploadMediaDetailAdapterUnitTest {
|
||||||
MockitoAnnotations.openMocks(this)
|
MockitoAnnotations.openMocks(this)
|
||||||
uploadMediaDetails = mutableListOf(uploadMediaDetail, uploadMediaDetail)
|
uploadMediaDetails = mutableListOf(uploadMediaDetail, uploadMediaDetail)
|
||||||
activity = Robolectric.buildActivity(UploadActivity::class.java).get()
|
activity = Robolectric.buildActivity(UploadActivity::class.java).get()
|
||||||
adapter = UploadMediaDetailAdapter("", recentLanguagesDao)
|
fragment = mock(UploadMediaDetailFragment::class.java)
|
||||||
|
adapter = UploadMediaDetailAdapter(fragment,"", recentLanguagesDao)
|
||||||
context = ApplicationProvider.getApplicationContext()
|
context = ApplicationProvider.getApplicationContext()
|
||||||
Whitebox.setInternalState(adapter, "uploadMediaDetails", uploadMediaDetails)
|
Whitebox.setInternalState(adapter, "uploadMediaDetails", uploadMediaDetails)
|
||||||
Whitebox.setInternalState(adapter, "eventListener", eventListener)
|
Whitebox.setInternalState(adapter, "eventListener", eventListener)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue