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:
Ayan Sarkar 2021-12-07 01:20:54 +05:30 committed by GitHub
parent e910b1d14f
commit 0269894c64
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 855 additions and 14 deletions

View 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()
}
}

View file

@ -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;
}
}

View file

@ -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";
}