mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Fix 4615: Option for editing caption and description (#4672)
* DescriptionEditHelper implemented * Description extracted * Description editable * No description condition handled * Code cleanup * Added javadocs * toolbar added * API call done * Caption edit available * Progress dialog added * Log * Problem with ButterKnife * Caption is editable * Removed unused import * Manifest file reverted * Manifest file reverted * Manifest file reverted * View binding added * Post operation test added * Java docs added * Java docs added * MediaDetailFragment unit tests added * Test added
This commit is contained in:
parent
e910b1d14f
commit
0269894c64
20 changed files with 855 additions and 14 deletions
|
|
@ -36,6 +36,10 @@
|
|||
android:requestLegacyExternalStorage = "true"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
|
||||
<activity
|
||||
android:name=".description.DescriptionEditActivity"
|
||||
android:exported="true" />
|
||||
|
||||
<activity android:name="org.acra.dialog.CrashReportDialog"
|
||||
android:process=":acra"
|
||||
android:launchMode="singleInstance"
|
||||
|
|
|
|||
|
|
@ -50,4 +50,9 @@ class MediaDataExtractor @Inject constructor(private val mediaClient: MediaClien
|
|||
}
|
||||
|
||||
fun getHtmlOfPage(title: String) = mediaClient.getPageHtml(title);
|
||||
|
||||
/**
|
||||
* Fetches wikitext from mediaClient
|
||||
*/
|
||||
fun getCurrentWikiText(title: String) = mediaClient.getCurrentWikiText(title);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,24 @@ class PageEditClient(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new labels to Wikibase server of commons
|
||||
* @param summary Edit summary
|
||||
* @param title Title of the page to edit
|
||||
* @param language Corresponding language of label
|
||||
* @param value label
|
||||
* @return 1 when the edit was successful
|
||||
*/
|
||||
fun setCaptions(summary: String, title: String,
|
||||
language: String, value: String) : Observable<Int>{
|
||||
return try {
|
||||
pageEditInterface.postCaptions(summary, title, language,
|
||||
value, csrfTokenClient.tokenBlocking).map { it.success }
|
||||
} catch (throwable: Throwable) {
|
||||
Observable.just(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whole WikiText of required file
|
||||
* @param title : Name of the file
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import io.reactivex.Single
|
|||
import org.wikipedia.dataclient.Service
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse
|
||||
import org.wikipedia.edit.Edit
|
||||
import org.wikipedia.wikidata.Entities
|
||||
import retrofit2.http.*
|
||||
|
||||
/**
|
||||
|
|
@ -73,6 +74,18 @@ interface PageEditInterface {
|
|||
@Field("token") token: String
|
||||
): Observable<Edit>
|
||||
|
||||
|
||||
@FormUrlEncoded
|
||||
@Headers("Cache-Control: no-cache")
|
||||
@POST(Service.MW_API_PREFIX + "action=wbsetlabel&format=json&site=commonswiki&formatversion=2")
|
||||
fun postCaptions(
|
||||
@Field("summary") summary: String,
|
||||
@Field("title") title: String,
|
||||
@Field("language") language: String,
|
||||
@Field("value") value: String,
|
||||
@Field("token") token: String
|
||||
): Observable<Entities>
|
||||
|
||||
/**
|
||||
* Get wiki text for provided file names
|
||||
* @param titles : Name of the file
|
||||
|
|
|
|||
|
|
@ -0,0 +1,181 @@
|
|||
package fr.free.nrw.commons.description
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.databinding.ActivityDescriptionEditBinding
|
||||
import fr.free.nrw.commons.description.EditDescriptionConstants.LIST_OF_DESCRIPTION_AND_CAPTION
|
||||
import fr.free.nrw.commons.description.EditDescriptionConstants.UPDATED_WIKITEXT
|
||||
import fr.free.nrw.commons.description.EditDescriptionConstants.WIKITEXT
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import fr.free.nrw.commons.settings.Prefs
|
||||
import fr.free.nrw.commons.upload.UploadMediaDetail
|
||||
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter
|
||||
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
/**
|
||||
* Activity for populating and editing existing description and caption
|
||||
*/
|
||||
class DescriptionEditActivity : AppCompatActivity(), UploadMediaDetailAdapter.EventListener {
|
||||
/**
|
||||
* Adapter for showing UploadMediaDetail in the activity
|
||||
*/
|
||||
private lateinit var uploadMediaDetailAdapter: UploadMediaDetailAdapter
|
||||
|
||||
/**
|
||||
* For getting default preference
|
||||
*/
|
||||
@JvmField
|
||||
@Inject
|
||||
@Named("default_preferences")
|
||||
var defaultKvStore: JsonKvStore? = null
|
||||
|
||||
/**
|
||||
* Recyclerview for recycling data in views
|
||||
*/
|
||||
@JvmField
|
||||
var rvDescriptions: RecyclerView? = null
|
||||
|
||||
/**
|
||||
* Current wikitext
|
||||
*/
|
||||
var wikiText: String? = null
|
||||
|
||||
/**
|
||||
* For showing progress dialog
|
||||
*/
|
||||
private var progressDialog: ProgressDialog? = null
|
||||
|
||||
private lateinit var binding: ActivityDescriptionEditBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityDescriptionEditBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
val bundle = intent.extras
|
||||
val descriptionAndCaptions: ArrayList<UploadMediaDetail> =
|
||||
bundle!!.getParcelableArrayList(LIST_OF_DESCRIPTION_AND_CAPTION)!!
|
||||
wikiText = bundle.getString(WIKITEXT)
|
||||
initRecyclerView(descriptionAndCaptions)
|
||||
|
||||
binding.btnAddDescription.setOnClickListener(::onButtonAddDescriptionClicked)
|
||||
binding.btnEditSubmit.setOnClickListener(::onSubmitButtonClicked)
|
||||
binding.toolbarBackButton.setOnClickListener(::onBackButtonClicked)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the RecyclerView
|
||||
* @param descriptionAndCaptions list of description and caption
|
||||
*/
|
||||
private fun initRecyclerView(descriptionAndCaptions: ArrayList<UploadMediaDetail>?) {
|
||||
uploadMediaDetailAdapter = UploadMediaDetailAdapter(
|
||||
defaultKvStore?.getString(Prefs.DESCRIPTION_LANGUAGE, ""),
|
||||
descriptionAndCaptions)
|
||||
uploadMediaDetailAdapter.setCallback { titleStringID: Int, messageStringId: Int ->
|
||||
showInfoAlert(
|
||||
titleStringID,
|
||||
messageStringId
|
||||
)
|
||||
}
|
||||
uploadMediaDetailAdapter.setEventListener(this)
|
||||
rvDescriptions = binding.rvDescriptionsCaptions
|
||||
rvDescriptions!!.layoutManager = LinearLayoutManager(this)
|
||||
rvDescriptions!!.adapter = uploadMediaDetailAdapter
|
||||
}
|
||||
|
||||
/**
|
||||
* show dialog with info
|
||||
* @param titleStringID Title ID
|
||||
* @param messageStringId Message ID
|
||||
*/
|
||||
private fun showInfoAlert(titleStringID: Int, messageStringId: Int) {
|
||||
showAlertDialog(
|
||||
this, getString(titleStringID),
|
||||
getString(messageStringId), getString(android.R.string.ok),
|
||||
null, true
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPrimaryCaptionTextChange(isNotEmpty: Boolean) {}
|
||||
|
||||
private fun onBackButtonClicked(view: View) {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
private fun onButtonAddDescriptionClicked(view: View) {
|
||||
val uploadMediaDetail = UploadMediaDetail()
|
||||
uploadMediaDetail.isManuallyAdded = true //This was manually added by the user
|
||||
uploadMediaDetailAdapter.addDescription(uploadMediaDetail)
|
||||
rvDescriptions!!.smoothScrollToPosition(uploadMediaDetailAdapter.itemCount - 1)
|
||||
}
|
||||
|
||||
private fun onSubmitButtonClicked(view: View) {
|
||||
showLoggingProgressBar()
|
||||
val uploadMediaDetails = uploadMediaDetailAdapter.items
|
||||
updateDescription(uploadMediaDetails)
|
||||
finish()
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates newly added descriptions in the wikiText and send to calling fragment
|
||||
* @param uploadMediaDetails descriptions and captions
|
||||
*/
|
||||
private fun updateDescription(uploadMediaDetails: List<UploadMediaDetail?>) {
|
||||
var descriptionIndex = wikiText!!.indexOf("description=")
|
||||
if (descriptionIndex == -1) {
|
||||
descriptionIndex = wikiText!!.indexOf("Description=")
|
||||
}
|
||||
val buffer = StringBuilder()
|
||||
if (descriptionIndex != -1) {
|
||||
val descriptionStart = wikiText!!.substring(0, descriptionIndex + 12)
|
||||
val descriptionToEnd = wikiText!!.substring(descriptionIndex + 12)
|
||||
val descriptionEndIndex = descriptionToEnd.indexOf("\n")
|
||||
val descriptionEnd = wikiText!!.substring(
|
||||
descriptionStart.length
|
||||
+ descriptionEndIndex
|
||||
)
|
||||
buffer.append(descriptionStart)
|
||||
for (i in uploadMediaDetails.indices) {
|
||||
val uploadDetails = uploadMediaDetails[i]
|
||||
if (uploadDetails!!.descriptionText != "") {
|
||||
buffer.append("{{")
|
||||
buffer.append(uploadDetails.languageCode)
|
||||
buffer.append("|1=")
|
||||
buffer.append(uploadDetails.descriptionText)
|
||||
buffer.append("}}, ")
|
||||
}
|
||||
}
|
||||
buffer.deleteCharAt(buffer.length - 1)
|
||||
buffer.deleteCharAt(buffer.length - 1)
|
||||
buffer.append(descriptionEnd)
|
||||
}
|
||||
val returningIntent = Intent()
|
||||
returningIntent.putExtra(UPDATED_WIKITEXT, buffer.toString())
|
||||
returningIntent.putParcelableArrayListExtra(
|
||||
LIST_OF_DESCRIPTION_AND_CAPTION,
|
||||
uploadMediaDetails as ArrayList<out Parcelable?>
|
||||
)
|
||||
setResult(RESULT_OK, returningIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun showLoggingProgressBar() {
|
||||
progressDialog = ProgressDialog(this)
|
||||
progressDialog!!.isIndeterminate = true
|
||||
progressDialog!!.setTitle(getString(R.string.updating_caption_title))
|
||||
progressDialog!!.setMessage(getString(R.string.updating_caption_message))
|
||||
progressDialog!!.setCanceledOnTouchOutside(false)
|
||||
progressDialog!!.show()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package fr.free.nrw.commons.description;
|
||||
|
||||
import static fr.free.nrw.commons.notification.NotificationHelper.NOTIFICATION_EDIT_DESCRIPTION;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.actions.PageEditClient;
|
||||
import fr.free.nrw.commons.notification.NotificationHelper;
|
||||
import io.reactivex.Single;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Helper class for edit and update given descriptions and showing notification upgradation
|
||||
*/
|
||||
public class DescriptionEditHelper {
|
||||
|
||||
/**
|
||||
* notificationHelper: helps creating notification
|
||||
*/
|
||||
private final NotificationHelper notificationHelper;
|
||||
/**
|
||||
* * pageEditClient: methods provided by this member posts the edited descriptions
|
||||
* to the Media wiki api
|
||||
*/
|
||||
public final PageEditClient pageEditClient;
|
||||
|
||||
@Inject
|
||||
public DescriptionEditHelper(final NotificationHelper notificationHelper,
|
||||
@Named("commons-page-edit") final PageEditClient pageEditClient) {
|
||||
this.notificationHelper = notificationHelper;
|
||||
this.pageEditClient = pageEditClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces new descriptions
|
||||
*
|
||||
* @param context context
|
||||
* @param media to be added
|
||||
* @param appendText to be added
|
||||
* @return Observable<Boolean>
|
||||
*/
|
||||
public Single<Boolean> addDescription(final Context context, final Media media,
|
||||
final String appendText) {
|
||||
Timber.d("thread is description adding %s", Thread.currentThread().getName());
|
||||
final String summary = "Updating Description";
|
||||
|
||||
return pageEditClient.edit(Objects.requireNonNull(media.getFilename()),
|
||||
appendText, summary)
|
||||
.flatMapSingle(result -> Single.just(showDescriptionEditNotification(context,
|
||||
media, result)))
|
||||
.firstOrError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new captions
|
||||
*
|
||||
* @param context context
|
||||
* @param media to be added
|
||||
* @param language to be added
|
||||
* @param value to be added
|
||||
* @return Observable<Boolean>
|
||||
*/
|
||||
public Single<Boolean> addCaption(final Context context, final Media media,
|
||||
final String language, final String value) {
|
||||
Timber.d("thread is caption adding %s", Thread.currentThread().getName());
|
||||
final String summary = "Updating Caption";
|
||||
|
||||
return pageEditClient.setCaptions(summary, Objects.requireNonNull(media.getFilename()),
|
||||
language, value)
|
||||
.flatMapSingle(result -> Single.just(showCaptionEditNotification(context,
|
||||
media, result)))
|
||||
.firstOrError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update captions and shows notification about captions update
|
||||
* @param context to be added
|
||||
* @param media to be added
|
||||
* @param result to be added
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean showCaptionEditNotification(final Context context, final Media media,
|
||||
final int result) {
|
||||
final String message;
|
||||
String title = context.getString(R.string.caption_edit_helper_show_edit_title);
|
||||
|
||||
if (result == 1) {
|
||||
title += ": " + context
|
||||
.getString(R.string.coordinates_edit_helper_show_edit_title_success);
|
||||
message = context.getString(R.string.caption_edit_helper_show_edit_message);
|
||||
} else {
|
||||
title += ": " + context.getString(R.string.caption_edit_helper_show_edit_title);
|
||||
message = context.getString(R.string.caption_edit_helper_edit_message_else) ;
|
||||
}
|
||||
|
||||
final String urlForFile = BuildConfig.COMMONS_URL + "/wiki/" + media.getFilename();
|
||||
final Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlForFile));
|
||||
notificationHelper.showNotification(context, title, message, NOTIFICATION_EDIT_DESCRIPTION,
|
||||
browserIntent);
|
||||
return result == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update descriptions and shows notification about descriptions update
|
||||
* @param context to be added
|
||||
* @param media to be added
|
||||
* @param result to be added
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean showDescriptionEditNotification(final Context context, final Media media,
|
||||
final boolean result) {
|
||||
final String message;
|
||||
String title = context.getString(R.string.description_edit_helper_show_edit_title);
|
||||
|
||||
if (result) {
|
||||
title += ": " + context
|
||||
.getString(R.string.coordinates_edit_helper_show_edit_title_success);
|
||||
message = context.getString(R.string.description_edit_helper_show_edit_message);
|
||||
} else {
|
||||
title += ": " + context.getString(R.string.description_edit_helper_show_edit_title);
|
||||
message = context.getString(R.string.description_edit_helper_edit_message_else) ;
|
||||
}
|
||||
|
||||
final String urlForFile = BuildConfig.COMMONS_URL + "/wiki/" + media.getFilename();
|
||||
final Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlForFile));
|
||||
notificationHelper.showNotification(context, title, message, NOTIFICATION_EDIT_DESCRIPTION,
|
||||
browserIntent);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package fr.free.nrw.commons.description
|
||||
|
||||
/**
|
||||
* For storing required constants for editing descriptions
|
||||
*/
|
||||
object EditDescriptionConstants {
|
||||
const val LIST_OF_DESCRIPTION_AND_CAPTION = "description.descriptionAndCaption"
|
||||
const val WIKITEXT = "description.wikiText"
|
||||
const val UPDATED_WIKITEXT = "description.updatedWikiText";
|
||||
}
|
||||
|
|
@ -157,6 +157,17 @@ class MediaClient @Inject constructor(
|
|||
fun resetUserNameContinuation(userName: String) =
|
||||
resetUserContinuation("user_", userName)
|
||||
|
||||
/**
|
||||
* Get whole WikiText of required file
|
||||
* @param title : Name of the file
|
||||
* @return Observable<MwQueryResult>
|
||||
*/
|
||||
fun getCurrentWikiText(title: String): Single<String?> {
|
||||
return mediaDetailInterface.getWikiText(title).map {
|
||||
it.query()?.pages()?.get(0)?.revisions()?.get(0)?.content()
|
||||
}
|
||||
}
|
||||
|
||||
override fun responseMapper(
|
||||
networkResult: Single<MwQueryResponse>,
|
||||
key: String?
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import static android.view.View.GONE;
|
|||
import static android.view.View.VISIBLE;
|
||||
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_NEEDING_CATEGORIES;
|
||||
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_UNCATEGORISED;
|
||||
import static fr.free.nrw.commons.description.EditDescriptionConstants.LIST_OF_DESCRIPTION_AND_CAPTION;
|
||||
import static fr.free.nrw.commons.description.EditDescriptionConstants.UPDATED_WIKITEXT;
|
||||
import static fr.free.nrw.commons.description.EditDescriptionConstants.WIKITEXT;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
|
|
@ -71,18 +74,23 @@ import fr.free.nrw.commons.contributions.ContributionsFragment;
|
|||
import fr.free.nrw.commons.coordinates.CoordinateEditHelper;
|
||||
import fr.free.nrw.commons.delete.DeleteHelper;
|
||||
import fr.free.nrw.commons.delete.ReasonBuilder;
|
||||
import fr.free.nrw.commons.description.DescriptionEditActivity;
|
||||
import fr.free.nrw.commons.description.DescriptionEditHelper;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.nearby.Label;
|
||||
import fr.free.nrw.commons.profile.ProfileActivity;
|
||||
import fr.free.nrw.commons.ui.widget.HtmlTextView;
|
||||
import fr.free.nrw.commons.upload.UploadMediaDetail;
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
|
@ -99,6 +107,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
CategoryEditHelper.Callback {
|
||||
|
||||
private static final int REQUEST_CODE = 1001 ;
|
||||
private static final int REQUEST_CODE_EDIT_DESCRIPTION = 1002 ;
|
||||
private boolean editable;
|
||||
private boolean isCategoryImage;
|
||||
private MediaDetailPagerFragment.MediaDetailProvider detailProvider;
|
||||
|
|
@ -136,6 +145,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
@Inject
|
||||
CoordinateEditHelper coordinateEditHelper;
|
||||
@Inject
|
||||
DescriptionEditHelper descriptionEditHelper;
|
||||
@Inject
|
||||
ViewUtilWrapper viewUtil;
|
||||
@Inject
|
||||
CategoryClient categoryClient;
|
||||
|
|
@ -225,6 +236,10 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
String descriptionHtmlCode;
|
||||
@BindView(R.id.progressBarDeletion)
|
||||
ProgressBar progressBarDeletion;
|
||||
@BindView(R.id.progressBarEdit)
|
||||
ProgressBar progressBarEditDescription;
|
||||
@BindView(R.id.description_edit)
|
||||
Button editDescription;
|
||||
|
||||
private ArrayList<String> categoryNames = new ArrayList<>();
|
||||
private String categorySearchQuery;
|
||||
|
|
@ -819,8 +834,155 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
.build(getActivity()), REQUEST_CODE);
|
||||
}
|
||||
|
||||
@OnClick(R.id.description_edit)
|
||||
public void onDescriptionEditClicked() {
|
||||
progressBarEditDescription.setVisibility(VISIBLE);
|
||||
editDescription.setVisibility(GONE);
|
||||
getDescriptionList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the coordinates and update the existing coordinates.
|
||||
* Gets descriptions from wikitext
|
||||
*/
|
||||
private void getDescriptionList() {
|
||||
compositeDisposable.add(mediaDataExtractor.getCurrentWikiText(
|
||||
Objects.requireNonNull(media.getFilename()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::extractCaptionDescription, Timber::e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets captions and descriptions and merge them according to language code and arranges it in a
|
||||
* single list.
|
||||
* Send the list to DescriptionEditActivity
|
||||
* @param s wikitext
|
||||
*/
|
||||
private void extractCaptionDescription(final String s) {
|
||||
final LinkedHashMap<String,String> descriptions = getDescriptions(s);
|
||||
final LinkedHashMap<String,String> captions = getCaptionsList();
|
||||
|
||||
final ArrayList<UploadMediaDetail> descriptionAndCaptions = new ArrayList<>();
|
||||
|
||||
if(captions.size() >= descriptions.size()) {
|
||||
for (final Map.Entry mapElement : captions.entrySet()) {
|
||||
|
||||
final String language = (String) mapElement.getKey();
|
||||
if (descriptions.containsKey(language)) {
|
||||
descriptionAndCaptions.add(
|
||||
new UploadMediaDetail(language,
|
||||
Objects.requireNonNull(descriptions.get(language)),
|
||||
(String) mapElement.getValue())
|
||||
);
|
||||
} else {
|
||||
descriptionAndCaptions.add(
|
||||
new UploadMediaDetail(language, "",
|
||||
(String) mapElement.getValue())
|
||||
);
|
||||
}
|
||||
}
|
||||
for (final Map.Entry mapElement : descriptions.entrySet()) {
|
||||
|
||||
final String language = (String) mapElement.getKey();
|
||||
if (!captions.containsKey(language)) {
|
||||
descriptionAndCaptions.add(
|
||||
new UploadMediaDetail(language,
|
||||
Objects.requireNonNull(descriptions.get(language)),
|
||||
"")
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (final Map.Entry mapElement : descriptions.entrySet()) {
|
||||
|
||||
final String language = (String) mapElement.getKey();
|
||||
if (captions.containsKey(language)) {
|
||||
descriptionAndCaptions.add(
|
||||
new UploadMediaDetail(language, (String) mapElement.getValue(),
|
||||
Objects.requireNonNull(captions.get(language)))
|
||||
);
|
||||
} else {
|
||||
descriptionAndCaptions.add(
|
||||
new UploadMediaDetail(language, (String) mapElement.getValue(),
|
||||
"")
|
||||
);
|
||||
}
|
||||
}
|
||||
for (final Map.Entry mapElement : captions.entrySet()) {
|
||||
|
||||
final String language = (String) mapElement.getKey();
|
||||
if (!descriptions.containsKey(language)) {
|
||||
descriptionAndCaptions.add(
|
||||
new UploadMediaDetail(language,
|
||||
"",
|
||||
Objects.requireNonNull(descriptions.get(language)))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
final Intent intent = new Intent(requireContext(), DescriptionEditActivity.class);
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putParcelableArrayList(LIST_OF_DESCRIPTION_AND_CAPTION, descriptionAndCaptions);
|
||||
bundle.putString(WIKITEXT, s);
|
||||
intent.putExtras(bundle);
|
||||
startActivityForResult(intent, REQUEST_CODE_EDIT_DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters descriptions from current wikiText and arranges it in LinkedHashmap according to the
|
||||
* language code
|
||||
* @param s wikitext
|
||||
* @return LinkedHashMap<LanguageCode,Description>
|
||||
*/
|
||||
private LinkedHashMap<String,String> getDescriptions(String s) {
|
||||
int descriptionIndex = s.indexOf("description=");
|
||||
if(descriptionIndex == -1){
|
||||
descriptionIndex = s.indexOf("Description=");
|
||||
}
|
||||
|
||||
if( descriptionIndex == -1 ){
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
final String descriptionToEnd = s.substring(descriptionIndex+12);
|
||||
final int descriptionEndIndex = descriptionToEnd.indexOf("\n");
|
||||
final String description = s.substring(descriptionIndex+12, descriptionIndex+12+descriptionEndIndex);
|
||||
|
||||
final String[] arr = description.trim().split(",");
|
||||
final LinkedHashMap<String,String> descriptionList = new LinkedHashMap<>();
|
||||
|
||||
if (!description.equals("")) {
|
||||
for (final String string :
|
||||
arr) {
|
||||
final int startCode = string.indexOf("{{");
|
||||
final int endCode = string.indexOf("|");
|
||||
final String languageCode = string.substring(startCode + 2, endCode).trim();
|
||||
final int startDescription = string.indexOf("=");
|
||||
final int endDescription = string.indexOf("}}");
|
||||
final String languageDescription = string
|
||||
.substring(startDescription + 1, endDescription);
|
||||
descriptionList.put(languageCode, languageDescription);
|
||||
}
|
||||
}
|
||||
return descriptionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of caption and arranges it in a LinkedHashmap according to the language code
|
||||
* @return LinkedHashMap<LanguageCode,Caption>
|
||||
*/
|
||||
private LinkedHashMap<String,String> getCaptionsList() {
|
||||
final LinkedHashMap<String, String> captionList = new LinkedHashMap<>();
|
||||
final Map<String, String> captions = media.getCaptions();
|
||||
for (final Map.Entry<String, String> map : captions.entrySet()) {
|
||||
final String language = map.getKey();
|
||||
final String languageCaption = map.getValue();
|
||||
captionList.put(language, languageCaption);
|
||||
}
|
||||
return captionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result from another activity and act accordingly.
|
||||
* @param requestCode
|
||||
* @param resultCode
|
||||
* @param data
|
||||
|
|
@ -854,13 +1016,61 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
updateCoordinates(latitude, longitude, accuracy);
|
||||
}
|
||||
}
|
||||
} else if (resultCode == RESULT_CANCELED) {
|
||||
|
||||
} else if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_OK) {
|
||||
final String updatedWikiText = data.getStringExtra(UPDATED_WIKITEXT);
|
||||
compositeDisposable.add(descriptionEditHelper.addDescription(getContext(), media,
|
||||
updatedWikiText)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(s -> {
|
||||
Timber.d("Descriptions are added.");
|
||||
}));
|
||||
|
||||
final ArrayList<UploadMediaDetail> uploadMediaDetails
|
||||
= data.getParcelableArrayListExtra(LIST_OF_DESCRIPTION_AND_CAPTION);
|
||||
|
||||
LinkedHashMap<String, String> updatedCaptions = new LinkedHashMap<>();
|
||||
for (UploadMediaDetail mediaDetail:
|
||||
uploadMediaDetails) {
|
||||
compositeDisposable.add(descriptionEditHelper.addCaption(getContext(), media,
|
||||
mediaDetail.getLanguageCode(), mediaDetail.getCaptionText())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(s -> {
|
||||
updateCaptions(mediaDetail, updatedCaptions);
|
||||
Timber.d("Caption is added.");
|
||||
}));
|
||||
}
|
||||
progressBarEditDescription.setVisibility(GONE);
|
||||
editDescription.setVisibility(VISIBLE);
|
||||
|
||||
} else if (requestCode == REQUEST_CODE && resultCode == RESULT_CANCELED) {
|
||||
viewUtil.showShortToast(getContext(),
|
||||
Objects.requireNonNull(getContext())
|
||||
.getString(R.string.coordinates_picking_unsuccessful));
|
||||
|
||||
} else if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_CANCELED) {
|
||||
progressBarEditDescription.setVisibility(GONE);
|
||||
editDescription.setVisibility(VISIBLE);
|
||||
|
||||
viewUtil.showShortToast(getContext(),
|
||||
Objects.requireNonNull(getContext())
|
||||
.getString(R.string.descriptions_picking_unsuccessful));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds caption to the map and updates captions
|
||||
* @param mediaDetail UploadMediaDetail
|
||||
* @param updatedCaptions updated captionds
|
||||
*/
|
||||
private void updateCaptions(UploadMediaDetail mediaDetail,
|
||||
LinkedHashMap<String, String> updatedCaptions) {
|
||||
updatedCaptions.put(mediaDetail.getLanguageCode(), mediaDetail.getCaptionText());
|
||||
media.setCaptions(updatedCaptions);
|
||||
}
|
||||
|
||||
@OnClick(R.id.update_categories_button)
|
||||
public void onUpdateCategoriesClicked() {
|
||||
updateCategories(categoryEditSearchRecyclerViewAdapter.getNewCategories());
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package fr.free.nrw.commons.media;
|
|||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import org.wikipedia.dataclient.Service;
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
|
||||
import org.wikipedia.wikidata.Entities;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
|
|
@ -35,4 +37,18 @@ public interface MediaDetailInterface {
|
|||
*/
|
||||
@GET("/w/api.php?action=wbgetentities&props=labels&format=json&languagefallback=1&sites=commonswiki")
|
||||
Observable<Entities> getEntityForImage(@Query("languages") String language, @Query("ids") String wikibaseIdentifier);
|
||||
|
||||
/**
|
||||
* Fetches current wikitext
|
||||
* @param title file name
|
||||
* @return Single<MwQueryResponse>
|
||||
*/
|
||||
@GET(
|
||||
Service.MW_API_PREFIX +
|
||||
"action=query&prop=revisions&rvprop=content|timestamp&rvlimit=1&converttitles="
|
||||
)
|
||||
Single<MwQueryResponse> getWikiText(
|
||||
@Query("titles") String title
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public class NotificationHelper {
|
|||
public static final int NOTIFICATION_DELETE = 1;
|
||||
public static final int NOTIFICATION_EDIT_CATEGORY = 2;
|
||||
public static final int NOTIFICATION_EDIT_COORDINATES = 3;
|
||||
public static final int NOTIFICATION_EDIT_DESCRIPTION = 4;
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder notificationBuilder;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
package fr.free.nrw.commons.upload
|
||||
|
||||
import android.os.Parcelable
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
/**
|
||||
* Holds a description of an item being uploaded by [UploadActivity]
|
||||
*/
|
||||
@Parcelize
|
||||
data class UploadMediaDetail constructor(
|
||||
/**
|
||||
* @return The language code ie. "en" or "fr"
|
||||
|
|
@ -15,7 +18,7 @@ data class UploadMediaDetail constructor(
|
|||
var languageCode: String? = null,
|
||||
var descriptionText: String = "",
|
||||
var captionText: String = ""
|
||||
) {
|
||||
) : Parcelable {
|
||||
fun javaCopy() = copy()
|
||||
|
||||
constructor(place: Place) : this(
|
||||
|
|
|
|||
|
|
@ -37,6 +37,13 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
|||
this.savedLanguageValue = savedLanguageValue;
|
||||
}
|
||||
|
||||
public UploadMediaDetailAdapter(final String savedLanguageValue,
|
||||
List<UploadMediaDetail> uploadMediaDetails) {
|
||||
this.uploadMediaDetails = uploadMediaDetails;
|
||||
selectedLanguages = new HashMap<>();
|
||||
this.savedLanguageValue = savedLanguageValue;
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
|
@ -51,6 +58,10 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public List<UploadMediaDetail> getItems(){
|
||||
return uploadMediaDetails;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
|
|
@ -178,14 +189,14 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
|||
long l) {
|
||||
description.setSelectedLanguageIndex(position);
|
||||
String languageCode = ((SpinnerLanguagesAdapter) adapterView.getAdapter())
|
||||
.getLanguageCode(position);
|
||||
.getLanguageCode(position);
|
||||
description.setLanguageCode(languageCode);
|
||||
selectedLanguages.remove(adapterView);
|
||||
selectedLanguages.put(adapterView, languageCode);
|
||||
((SpinnerLanguagesAdapter) adapterView
|
||||
.getAdapter()).setSelectedLangCode(languageCode);
|
||||
.getAdapter()).setSelectedLangCode(languageCode);
|
||||
spinnerDescriptionLanguages.setSelection(position);
|
||||
Timber.d("Description language code is: "+languageCode);
|
||||
Timber.d("Description language code is: " + languageCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -198,8 +209,16 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
|||
if (!TextUtils.isEmpty(savedLanguageValue)) {
|
||||
// If user has chosen a default language from settings activity
|
||||
// savedLanguageValue is not null
|
||||
if(!TextUtils.isEmpty(description.getLanguageCode())) {
|
||||
spinnerDescriptionLanguages.setSelection(languagesAdapter
|
||||
.getIndexOfLanguageCode(description.getLanguageCode()));
|
||||
} else {
|
||||
spinnerDescriptionLanguages.setSelection(languagesAdapter
|
||||
.getIndexOfLanguageCode(savedLanguageValue));
|
||||
}
|
||||
} else if (!TextUtils.isEmpty(description.getLanguageCode())) {
|
||||
spinnerDescriptionLanguages.setSelection(languagesAdapter
|
||||
.getIndexOfLanguageCode(savedLanguageValue));
|
||||
.getIndexOfLanguageCode(description.getLanguageCode()));
|
||||
} else {
|
||||
//Checking whether Language Code attribute is null or not.
|
||||
if (uploadMediaDetails.get(position).getLanguageCode() != null) {
|
||||
|
|
|
|||
80
app/src/main/res/layout/activity_description_edit.xml
Normal file
80
app/src/main/res/layout/activity_description_edit.xml
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".description.DescriptionEditActivity">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/primaryColor"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/toolbar_text_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="72dp"
|
||||
android:text="@string/description_activity_title"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/toolbar_back_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:contentDescription="@string/exit_location_picker"
|
||||
android:tint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_arrow_back_white" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_descriptions_captions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/edit_bottom_layout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/edit_bottom_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">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btn_add_description"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="@dimen/fragment_height"
|
||||
android:text="+" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btn_edit_submit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:text="@string/submit"
|
||||
android:textColor="@android:color/white" />
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -204,16 +204,44 @@
|
|||
android:textSize="@dimen/description_text_size"
|
||||
android:textIsSelectable="true"
|
||||
tools:text="Description of the media goes here. This can potentially be fairly long, and will need to wrap across multiple lines. We hope it looks nice though." />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/show_caption_description_textview"
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
<LinearLayout
|
||||
android:paddingStart="@dimen/quarter_standard_height"
|
||||
android:paddingEnd="@dimen/quarter_standard_height"
|
||||
android:layout_width="match_parent"
|
||||
android:gravity="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dimen_10"
|
||||
android:text="@string/media_detail_in_all_languages" />
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/show_caption_description_textview"
|
||||
style="@style/MediaDetailTextLabelGeneric"
|
||||
android:layout_width="match_parent"
|
||||
android:gravity="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dimen_10"
|
||||
android:text="@string/media_detail_in_all_languages" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/description_edit"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="end"
|
||||
android:background="@drawable/ic_baseline_edit_24" />
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBarEdit"
|
||||
style="?android:progressBarStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/tiny_gap"
|
||||
android:layout_marginRight="@dimen/tiny_gap"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:indeterminate="true"
|
||||
android:indeterminateOnly="true"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:background="?attr/mediaDetailSpacerColor"
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
<string name="signup">Sign up</string>
|
||||
<string name="logging_in_title">Logging in</string>
|
||||
<string name="logging_in_message">Please wait…</string>
|
||||
<string name="updating_caption_title">Updating captions and descriptions</string>
|
||||
<string name="updating_caption_message">Please wait…</string>
|
||||
<string name="login_success">Login success!</string>
|
||||
<string name="login_failed">Login failed!</string>
|
||||
<string name="upload_failed">File not found. Please try another file.</string>
|
||||
|
|
@ -371,7 +373,7 @@
|
|||
<string name="next">Next</string>
|
||||
<string name="previous">Previous</string>
|
||||
<string name="submit">Submit</string>
|
||||
<string formatted="true" name="upload_title_duplicate">A file with the file name %1$s exists. Are you sure you want to proceed?\n\nNote: A suitable suffix will be added to the file name automatically.</string>
|
||||
<string name="upload_title_duplicate" formatted="true">A file with the file name %1$s exists. Are you sure you want to proceed?\n\nNote: A suitable suffix will be added to the file name automatically.</string>
|
||||
<string name="map_application_missing">No compatible map application could be found on your device. Please install a map application to use this feature.</string>
|
||||
<string name="title_page_bookmarks_pictures">Pictures</string>
|
||||
<string name="title_page_bookmarks_locations">Locations</string>
|
||||
|
|
@ -521,10 +523,18 @@ Upload your first media by tapping on the add button.</string>
|
|||
|
||||
<string name="coordinates_edit_helper_make_edit_toast">Trying to update coordinates.</string>
|
||||
<string name="coordinates_edit_helper_show_edit_title">Coordinates update</string>
|
||||
<string name="description_edit_helper_show_edit_title">Description update</string>
|
||||
<string name="caption_edit_helper_show_edit_title">Caption update</string>
|
||||
<string name="coordinates_edit_helper_show_edit_title_success">Success</string>
|
||||
<string name="coordinates_edit_helper_show_edit_message">Coordinates %1$s are added.</string>
|
||||
<string name="description_edit_helper_show_edit_message">Descriptions are added.</string>
|
||||
<string name="caption_edit_helper_show_edit_message">Caption is added.</string>
|
||||
<string name="coordinates_edit_helper_edit_message_else">Could not add coordinates.</string>
|
||||
<string name="description_edit_helper_edit_message_else">Could not add descriptions.</string>
|
||||
<string name="caption_edit_helper_edit_message_else">Could not add caption.</string>
|
||||
<string name="coordinates_picking_unsuccessful">Unable to get coordinates.</string>
|
||||
<string name="descriptions_picking_unsuccessful">Unable to get descriptions.</string>
|
||||
<string name="description_activity_title">Edit descriptions and captions</string>
|
||||
|
||||
<string name="share_image_via">Share image via</string>
|
||||
<string name="you_have_no_achievements_yet">You haven\'t made any contributions yet</string>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons
|
||||
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
import io.reactivex.Single
|
||||
import org.junit.Assert.assertTrue
|
||||
|
|
@ -11,6 +12,7 @@ import org.mockito.Mock
|
|||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse
|
||||
|
||||
/**
|
||||
* Test methods in media data extractor
|
||||
|
|
@ -49,4 +51,10 @@ class MediaDataExtractorTest {
|
|||
|
||||
//assertTrue(fetchMediaDetails is Media)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getWikiText() {
|
||||
`when`(mediaDataExtractor?.getCurrentWikiText(ArgumentMatchers.anyString()))
|
||||
.thenReturn(Single.just("Test"))
|
||||
}
|
||||
}
|
||||
|
|
@ -81,4 +81,15 @@ class PageEditClientTest {
|
|||
pageEditClient.prependEdit("test", "test", "test")
|
||||
verify(pageEditInterface).postPrependEdit(eq("test"), eq("test"), eq("test"), eq("test"))
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setCaptions
|
||||
*/
|
||||
@Test
|
||||
fun testSetCaptions() {
|
||||
Mockito.`when`(csrfTokenClient.tokenBlocking).thenReturn("test")
|
||||
pageEditClient.setCaptions("test", "test", "en", "test")
|
||||
verify(pageEditInterface).postCaptions(eq("test"), eq("test"), eq("en"),
|
||||
eq("test"), eq("test"))
|
||||
}
|
||||
}
|
||||
|
|
@ -199,6 +199,12 @@ class MediaClientTest {
|
|||
mediaClient.doesPageContainMedia("").test().assertValue(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getWikiText() {
|
||||
val wikiText = mock<MwQueryResponse>()
|
||||
whenever(mediaDetailInterface.getWikiText("File:Test.jpg")).thenReturn(Single.just(wikiText))
|
||||
}
|
||||
|
||||
private fun mockQuery(queryReceiver: MwQueryResult.() -> Unit): MwQueryResponse {
|
||||
val mwQueryResponse = mock<MwQueryResponse>()
|
||||
val mwQueryResult = mock<MwQueryResult>()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package fr.free.nrw.commons.media
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
|
@ -49,6 +51,9 @@ import kotlin.collections.HashMap
|
|||
@LooperMode(LooperMode.Mode.PAUSED)
|
||||
class MediaDetailFragmentUnitTests {
|
||||
|
||||
|
||||
private val REQUEST_CODE = 1001
|
||||
private val REQUEST_CODE_EDIT_DESCRIPTION = 1002
|
||||
private lateinit var fragment: MediaDetailFragment
|
||||
private lateinit var fragmentManager: FragmentManager
|
||||
private lateinit var layoutInflater: LayoutInflater
|
||||
|
|
@ -106,6 +111,9 @@ class MediaDetailFragmentUnitTests {
|
|||
@Mock
|
||||
private lateinit var searchView: SearchView
|
||||
|
||||
@Mock
|
||||
private lateinit var intent: Intent
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
|
||||
|
|
@ -140,6 +148,7 @@ class MediaDetailFragmentUnitTests {
|
|||
|
||||
Whitebox.setInternalState(fragment, "media", media)
|
||||
Whitebox.setInternalState(fragment, "progressBar", progressBar)
|
||||
Whitebox.setInternalState(fragment, "progressBarEditDescription", progressBar)
|
||||
Whitebox.setInternalState(fragment, "captionsListView", listView)
|
||||
Whitebox.setInternalState(fragment, "descriptionWebView", webView)
|
||||
Whitebox.setInternalState(fragment, "detailProvider", detailProvider)
|
||||
|
|
@ -159,6 +168,7 @@ class MediaDetailFragmentUnitTests {
|
|||
Whitebox.setInternalState(fragment, "dummyCategoryEditContainer", linearLayout)
|
||||
Whitebox.setInternalState(fragment, "showCaptionAndDescriptionContainer", linearLayout)
|
||||
Whitebox.setInternalState(fragment, "updateCategoriesButton", button)
|
||||
Whitebox.setInternalState(fragment, "editDescription", button)
|
||||
Whitebox.setInternalState(fragment, "categoryContainer", linearLayout)
|
||||
Whitebox.setInternalState(fragment, "categorySearchView", searchView)
|
||||
Whitebox.setInternalState(fragment, "mediaDiscussion", textView)
|
||||
|
|
@ -188,6 +198,24 @@ class MediaDetailFragmentUnitTests {
|
|||
fragment.onCreateView(layoutInflater, null, savedInstanceState)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testOnActivityResultLocationPickerActivity() {
|
||||
fragment.onActivityResult(REQUEST_CODE, Activity.RESULT_CANCELED, intent)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun `test OnActivity Result Cancelled LocationPickerActivity`() {
|
||||
fragment.onActivityResult(REQUEST_CODE, Activity.RESULT_CANCELED, intent)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun `test OnActivity Result Cancelled DescriptionEditActivity`() {
|
||||
fragment.onActivityResult(REQUEST_CODE, Activity.RESULT_OK, intent)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testOnSaveInstanceState() {
|
||||
|
|
@ -252,6 +280,17 @@ class MediaDetailFragmentUnitTests {
|
|||
method.invoke(fragment)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testGetDescriptionList() {
|
||||
`when`(media.filename).thenReturn("")
|
||||
val method: Method = MediaDetailFragment::class.java.getDeclaredMethod(
|
||||
"getDescriptionList"
|
||||
)
|
||||
method.isAccessible = true
|
||||
method.invoke(fragment)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testGetCaptions() {
|
||||
|
|
@ -301,6 +340,15 @@ class MediaDetailFragmentUnitTests {
|
|||
Assert.assertEquals(fragment.updateCategoryDisplay(listOf()), true)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testDescriptionEditClicked() {
|
||||
`when`(progressBar.visibility).thenReturn(View.VISIBLE)
|
||||
`when`(button.visibility).thenReturn(View.GONE)
|
||||
`when`(media.filename).thenReturn("")
|
||||
fragment.onDescriptionEditClicked()
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testShowCaptionAndDescriptionCaseVisible() {
|
||||
|
|
@ -397,6 +445,28 @@ class MediaDetailFragmentUnitTests {
|
|||
method.invoke(fragment, "mock")
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testExtractCaptionDescription() {
|
||||
val method: Method = MediaDetailFragment::class.java.getDeclaredMethod(
|
||||
"extractCaptionDescription",
|
||||
String::class.java
|
||||
)
|
||||
method.isAccessible = true
|
||||
method.invoke(fragment, "mock")
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testGetDescriptions() {
|
||||
val method: Method = MediaDetailFragment::class.java.getDeclaredMethod(
|
||||
"getDescriptions",
|
||||
String::class.java
|
||||
)
|
||||
method.isAccessible = true
|
||||
method.invoke(fragment, "mock")
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testPrettyCaptionCaseEmpty() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue