mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
Fixed 4616 : Option for editing depictions (#4725)
* Dialog can't be dismissed * Dialog can't be dismissed * Option for editing depiction * Java docs added * Minor issues fixed * Lining done * "Depictions not updating instantly" issue resolved * Existing Depicts on the top * Existing Depicts on the top * Back press handled * Previous depictions unchecked * Whole Screen issue fixed * Nearby banner removed * Test fixed * Upload Wizard issue fixed * Upload Wizard issue fixed * Previous depicts issue fixed * Previous depicts issue fixed * All issues fixed * Fixed late loading of updated depicts * Depiction is removable * Test fixed * Back button press handled after losing focus for edittext * RequiresApi removed * RequiresApi removed * Test fixed * Requested changes * Test added * Test added * UploadModelUnitTest added * DepictEditHelperUnitTest added * DepictEditHelperUnitTest added * Test added * More test added * Indentation Reversed * Indentation reversed * Update MediaDetailFragment.java * Indentation reversed * Update MediaDetailFragment.java * Indentation reversed * Indentation reversed * Indentation reversed * Indentation reversed * More test added * More test added * Minor fixes * Minor fixes * Minor fixes
This commit is contained in:
parent
e58322ed63
commit
bd9531b969
24 changed files with 1261 additions and 75 deletions
|
|
@ -125,6 +125,16 @@ public class MainActivity extends BaseActivity
|
|||
toolbar.setNavigationOnClickListener(view -> {
|
||||
onSupportNavigateUp();
|
||||
});
|
||||
/*
|
||||
"first_edit_depict" is a key for getting information about opening the depiction editor
|
||||
screen for the first time after opening the app.
|
||||
|
||||
Getting true by the key means the depiction editor screen is opened for the first time
|
||||
after opening the app.
|
||||
Getting false by the key means the depiction editor screen is not opened for the first time
|
||||
after opening the app.
|
||||
*/
|
||||
applicationKvStore.putBoolean("first_edit_depict", true);
|
||||
if (applicationKvStore.getBoolean("login_skipped") == true) {
|
||||
setTitle(getString(R.string.navigation_item_explore));
|
||||
setUpLoggedOutPager();
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@ import static fr.free.nrw.commons.description.EditDescriptionConstants.LIST_OF_D
|
|||
import static fr.free.nrw.commons.description.EditDescriptionConstants.UPDATED_WIKITEXT;
|
||||
import static fr.free.nrw.commons.description.EditDescriptionConstants.WIKITEXT;
|
||||
import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_LOCATION;
|
||||
import android.content.res.Resources;
|
||||
import static fr.free.nrw.commons.utils.LangCodeUtils.getLocalizedResources;
|
||||
import android.annotation.SuppressLint;
|
||||
import java.lang.reflect.Field;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
|
@ -45,6 +43,8 @@ import android.widget.Spinner;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
|
|
@ -86,6 +86,7 @@ import fr.free.nrw.commons.location.LocationServiceManager;
|
|||
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.depicts.DepictsFragment;
|
||||
import fr.free.nrw.commons.upload.UploadMediaDetail;
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper;
|
||||
import io.reactivex.Single;
|
||||
|
|
@ -93,7 +94,6 @@ 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;
|
||||
|
|
@ -176,6 +176,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
LinearLayout captionLayout;
|
||||
@BindView(R.id.depicts_layout)
|
||||
LinearLayout depictsLayout;
|
||||
@BindView(R.id.depictionsEditButton)
|
||||
Button depictEditButton;
|
||||
@BindView(R.id.media_detail_caption)
|
||||
TextView mediaCaption;
|
||||
@BindView(R.id.mediaDetailDesc)
|
||||
|
|
@ -239,7 +241,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
@BindView(R.id.description_label)
|
||||
TextView descriptionLabel;
|
||||
@BindView(R.id.pb_circular)
|
||||
ProgressBar progressBar;
|
||||
ProgressBar progressBar;
|
||||
String descriptionHtmlCode;
|
||||
@BindView(R.id.progressBarDeletion)
|
||||
ProgressBar progressBarDeletion;
|
||||
|
|
@ -467,10 +469,10 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
private void displayMediaDetails() {
|
||||
setTextFields(media);
|
||||
compositeDisposable.addAll(
|
||||
mediaDataExtractor.fetchDepictionIdsAndLabels(media)
|
||||
mediaDataExtractor.refresh(media)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::onDepictionsLoaded, Timber::e),
|
||||
.subscribe(this::onMediaRefreshed, Timber::e),
|
||||
mediaDataExtractor.checkDeletionRequestExists(media)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
|
@ -478,15 +480,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
mediaDataExtractor.fetchDiscussion(media)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::onDiscussionLoaded, Timber::e),
|
||||
mediaDataExtractor.refresh(media)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::onMediaRefreshed, Timber::e)
|
||||
.subscribe(this::onDiscussionLoaded, Timber::e)
|
||||
);
|
||||
}
|
||||
|
||||
private void onMediaRefreshed(Media media) {
|
||||
this.media = media;
|
||||
setTextFields(media);
|
||||
compositeDisposable.addAll(
|
||||
mediaDataExtractor.fetchDepictionIdsAndLabels(media)
|
||||
|
|
@ -517,8 +516,26 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
}
|
||||
|
||||
private void onDepictionsLoaded(List<IdAndCaptions> idAndCaptions){
|
||||
depictsLayout.setVisibility(idAndCaptions.isEmpty() ? GONE : VISIBLE);
|
||||
buildDepictionList(idAndCaptions);
|
||||
depictsLayout.setVisibility(idAndCaptions.isEmpty() ? GONE : VISIBLE);
|
||||
depictEditButton.setVisibility(idAndCaptions.isEmpty() ? GONE : VISIBLE);
|
||||
buildDepictionList(idAndCaptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* By clicking on the edit depictions button, it will send user to depict fragment
|
||||
*/
|
||||
@OnClick(R.id.depictionsEditButton)
|
||||
public void onDepictionsEditButtonClicked() {
|
||||
depictionContainer.removeAllViews();
|
||||
depictEditButton.setVisibility(GONE);
|
||||
final Fragment depictsFragment = new DepictsFragment();
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putParcelable("Existing_Depicts", media);
|
||||
depictsFragment.setArguments(bundle);
|
||||
final FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
|
||||
transaction.replace(R.id.mediaDetailFrameLayout, depictsFragment);
|
||||
transaction.addToBackStack(null);
|
||||
transaction.commit();
|
||||
}
|
||||
/**
|
||||
* The imageSpacer is Basically a transparent overlay for the SimpleDraweeView
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public class NotificationHelper {
|
|||
public static final int NOTIFICATION_EDIT_CATEGORY = 2;
|
||||
public static final int NOTIFICATION_EDIT_COORDINATES = 3;
|
||||
public static final int NOTIFICATION_EDIT_DESCRIPTION = 4;
|
||||
public static final int NOTIFICATION_EDIT_DEPICTIONS = 5;
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder notificationBuilder;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package fr.free.nrw.commons.repository;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.category.CategoriesModel;
|
||||
import fr.free.nrw.commons.category.CategoryItem;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
|
|
@ -233,8 +234,8 @@ public class UploadRepository {
|
|||
uploadModel.setSelectedLicense(licenseName);
|
||||
}
|
||||
|
||||
public void onDepictItemClicked(DepictedItem depictedItem) {
|
||||
uploadModel.onDepictItemClicked(depictedItem);
|
||||
public void onDepictItemClicked(DepictedItem depictedItem, final Media media) {
|
||||
uploadModel.onDepictItemClicked(depictedItem, media);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -247,6 +248,23 @@ public class UploadRepository {
|
|||
return uploadModel.getSelectedDepictions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides selected existing depicts
|
||||
*
|
||||
* @return selected existing depicts
|
||||
*/
|
||||
public List<String> getSelectedExistingDepictions() {
|
||||
return uploadModel.getSelectedExistingDepictions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize existing depicts
|
||||
*
|
||||
* @param selectedExistingDepictions existing depicts
|
||||
*/
|
||||
public void setSelectedExistingDepictions(final List<String> selectedExistingDepictions) {
|
||||
uploadModel.setSelectedExistingDepictions(selectedExistingDepictions);
|
||||
}
|
||||
/**
|
||||
* Search all depictions from
|
||||
*
|
||||
|
|
@ -275,6 +293,39 @@ public class UploadRepository {
|
|||
return depictModel.getPlaceDepictions(new ArrayList<>(qids));
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes depict IDs as a parameter, converts into a slash separated String and Gets DepictItem
|
||||
* from the server
|
||||
*
|
||||
* @param depictionsQIDs IDs of Depiction
|
||||
* @return Flowable<List<DepictedItem>>
|
||||
*/
|
||||
public Flowable<List<DepictedItem>> getDepictions(final List<String> depictionsQIDs){
|
||||
final String ids = joinQIDs(depictionsQIDs);
|
||||
return depictModel.getDepictions(ids).toFlowable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a string by joining all IDs divided by "|"
|
||||
*
|
||||
* @param depictionsQIDs IDs of depiction ex. ["Q11023","Q1356"]
|
||||
* @return string ex. "Q11023|Q1356"
|
||||
*/
|
||||
private String joinQIDs(final List<String> depictionsQIDs) {
|
||||
if (depictionsQIDs != null && !depictionsQIDs.isEmpty()) {
|
||||
final StringBuilder buffer = new StringBuilder(depictionsQIDs.get(0));
|
||||
|
||||
if (depictionsQIDs.size() > 1) {
|
||||
for (int i = 1; i < depictionsQIDs.size(); i++) {
|
||||
buffer.append("|");
|
||||
buffer.append(depictionsQIDs.get(i));
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns nearest place matching the passed latitude and longitude
|
||||
* @param decLatitude
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.upload;
|
|||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||
|
|
@ -40,6 +41,10 @@ public class UploadModel {
|
|||
private final ImageProcessingService imageProcessingService;
|
||||
private final List<String> selectedCategories = new ArrayList<>();
|
||||
private final List<DepictedItem> selectedDepictions = new ArrayList<>();
|
||||
/**
|
||||
* Existing depicts which are selected
|
||||
*/
|
||||
private List<String> selectedExistingDepictions = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
UploadModel(@Named("licenses") final List<String> licenses,
|
||||
|
|
@ -68,6 +73,7 @@ public class UploadModel {
|
|||
items.clear();
|
||||
selectedCategories.clear();
|
||||
selectedDepictions.clear();
|
||||
selectedExistingDepictions.clear();
|
||||
}
|
||||
|
||||
public void setSelectedCategories(List<String> selectedCategories) {
|
||||
|
|
@ -185,11 +191,33 @@ public class UploadModel {
|
|||
return items;
|
||||
}
|
||||
|
||||
public void onDepictItemClicked(DepictedItem depictedItem) {
|
||||
if (depictedItem.isSelected()) {
|
||||
selectedDepictions.add(depictedItem);
|
||||
public void onDepictItemClicked(DepictedItem depictedItem, Media media) {
|
||||
if (media == null) {
|
||||
if (depictedItem.isSelected()) {
|
||||
selectedDepictions.add(depictedItem);
|
||||
} else {
|
||||
selectedDepictions.remove(depictedItem);
|
||||
}
|
||||
} else {
|
||||
selectedDepictions.remove(depictedItem);
|
||||
if (depictedItem.isSelected()) {
|
||||
if (media.getDepictionIds().contains(depictedItem.getId())) {
|
||||
selectedExistingDepictions.add(depictedItem.getId());
|
||||
} else {
|
||||
selectedDepictions.add(depictedItem);
|
||||
}
|
||||
} else {
|
||||
if (media.getDepictionIds().contains(depictedItem.getId())) {
|
||||
selectedExistingDepictions.remove(depictedItem.getId());
|
||||
if (!media.getDepictionIds().contains(depictedItem.getId())) {
|
||||
final List<String> depictsList = new ArrayList<>();
|
||||
depictsList.add(depictedItem.getId());
|
||||
depictsList.addAll(media.getDepictionIds());
|
||||
media.setDepictionIds(depictsList);
|
||||
}
|
||||
} else {
|
||||
selectedDepictions.remove(depictedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -207,4 +235,21 @@ public class UploadModel {
|
|||
return selectedDepictions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides selected existing depicts
|
||||
*
|
||||
* @return selected existing depicts
|
||||
*/
|
||||
public List<String> getSelectedExistingDepictions() {
|
||||
return selectedExistingDepictions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize existing depicts
|
||||
*
|
||||
* @param selectedExistingDepictions existing depicts
|
||||
*/
|
||||
public void setSelectedExistingDepictions(final List<String> selectedExistingDepictions) {
|
||||
this.selectedExistingDepictions = selectedExistingDepictions;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,21 @@ public interface WikiBaseInterface {
|
|||
@NonNull @Field("token") String editToken,
|
||||
@NonNull @Field("data") String data);
|
||||
|
||||
/**
|
||||
* Uploads depicts for a file in the server
|
||||
*
|
||||
* @param filename name of the file
|
||||
* @param editToken editToken for the file
|
||||
* @param data data of the depicts to be uploaded
|
||||
* @return Observable<MwPostResponse>
|
||||
*/
|
||||
@Headers("Cache-Control: no-cache")
|
||||
@FormUrlEncoded
|
||||
@POST(MW_API_PREFIX + "action=wbeditentity&site=commonswiki&clear=1")
|
||||
Observable<MwPostResponse> postEditEntityByFilename(@NonNull @Field("title") String filename,
|
||||
@NonNull @Field("token") String editToken,
|
||||
@NonNull @Field("data") String data);
|
||||
|
||||
@GET(MW_API_PREFIX + "action=query&prop=info")
|
||||
Observable<MwQueryResponse> getFileEntityId(@Query("titles") String fileName);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
package fr.free.nrw.commons.upload.depicts
|
||||
|
||||
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.notification.NotificationHelper
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper
|
||||
import fr.free.nrw.commons.wikidata.WikidataEditService
|
||||
import io.reactivex.Observable
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class DepictEditHelper @Inject constructor (notificationHelper: NotificationHelper,
|
||||
wikidataEditService: WikidataEditService,
|
||||
viewUtilWrapper: ViewUtilWrapper) {
|
||||
|
||||
/**
|
||||
* Class for making post operations
|
||||
*/
|
||||
@Inject
|
||||
lateinit var wikidataEditService: WikidataEditService
|
||||
|
||||
/**
|
||||
* Class for creating notification
|
||||
*/
|
||||
@Inject
|
||||
lateinit var notificationHelper: NotificationHelper
|
||||
|
||||
/**
|
||||
* Class for showing toast
|
||||
*/
|
||||
@Inject
|
||||
lateinit var viewUtilWrapper: ViewUtilWrapper
|
||||
|
||||
/**
|
||||
* Public interface to edit depictions
|
||||
*
|
||||
* @param context context
|
||||
* @param media media
|
||||
* @param depictions selected depictions to be added ex: ["Q12", "Q234"]
|
||||
* @return Single<Boolean>
|
||||
*/
|
||||
fun makeDepictionEdit(
|
||||
context: Context,
|
||||
media: Media,
|
||||
depictions: List<String>
|
||||
): Observable<Boolean> {
|
||||
viewUtilWrapper.showShortToast(
|
||||
context,
|
||||
context.getString(R.string.depictions_edit_helper_make_edit_toast)
|
||||
)
|
||||
return addDepiction(media, depictions)
|
||||
.flatMap { result: Boolean ->
|
||||
Observable.just(
|
||||
showDepictionEditNotification(context, media, result)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends new depictions
|
||||
*
|
||||
* @param media media
|
||||
* @param depictions to be added
|
||||
* @return Observable<Boolean>
|
||||
*/
|
||||
private fun addDepiction(media: Media, depictions: List<String>): Observable<Boolean> {
|
||||
Timber.d("thread is adding depiction %s", Thread.currentThread().name)
|
||||
return wikidataEditService.updateDepictsProperty(media.filename, depictions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helps to create notification about condition of editing depictions
|
||||
*
|
||||
* @param context context
|
||||
* @param media media
|
||||
* @param result response of result
|
||||
* @return Single<Boolean>
|
||||
*/
|
||||
private fun showDepictionEditNotification(
|
||||
context: Context,
|
||||
media: Media,
|
||||
result: Boolean
|
||||
): Boolean {
|
||||
val message: String
|
||||
var title = context.getString(R.string.depictions_edit_helper_show_edit_title)
|
||||
if (result) {
|
||||
title += ": " + context.getString(R.string.category_edit_helper_show_edit_title_success)
|
||||
val depictsInMessage = StringBuilder()
|
||||
val depictIdList = media.depictionIds
|
||||
for (depiction in depictIdList) {
|
||||
depictsInMessage.append(depiction)
|
||||
if (depiction == depictIdList[depictIdList.size - 1]) {
|
||||
continue
|
||||
}
|
||||
depictsInMessage.append(",")
|
||||
}
|
||||
message = context.resources.getQuantityString(
|
||||
R.plurals.depictions_edit_helper_show_edit_message_if,
|
||||
depictIdList.size,
|
||||
depictsInMessage.toString()
|
||||
)
|
||||
} else {
|
||||
title += ": " + context.getString(R.string.depictions_edit_helper_show_edit_title)
|
||||
message = context.getString(R.string.depictions_edit_helper_edit_message_else)
|
||||
}
|
||||
val urlForFile = BuildConfig.COMMONS_URL + "/wiki/" + media.filename
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(urlForFile))
|
||||
notificationHelper.showNotification(
|
||||
context,
|
||||
title,
|
||||
message,
|
||||
NotificationHelper.NOTIFICATION_EDIT_DEPICTIONS,
|
||||
browserIntent
|
||||
)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
package fr.free.nrw.commons.upload.depicts;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import fr.free.nrw.commons.BasePresenter;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -40,6 +43,36 @@ public interface DepictsContract {
|
|||
* add depictions to list
|
||||
*/
|
||||
void setDepictsList(List<DepictedItem> depictedItemList);
|
||||
|
||||
/**
|
||||
* Returns required context
|
||||
*/
|
||||
Context getFragmentContext();
|
||||
|
||||
/**
|
||||
* Returns to previous fragment
|
||||
*/
|
||||
void goBackToPreviousScreen();
|
||||
|
||||
/**
|
||||
* Gets existing depictions IDs from media
|
||||
*/
|
||||
List<String> getExistingDepictions();
|
||||
|
||||
/**
|
||||
* Shows the progress dialog
|
||||
*/
|
||||
void showProgressDialog();
|
||||
|
||||
/**
|
||||
* Hides the progress dialog
|
||||
*/
|
||||
void dismissProgressDialog();
|
||||
|
||||
/**
|
||||
* Update the depictions
|
||||
*/
|
||||
void updateDepicts();
|
||||
}
|
||||
|
||||
interface UserActionListener extends BasePresenter<View> {
|
||||
|
|
@ -71,6 +104,21 @@ public interface DepictsContract {
|
|||
*/
|
||||
void verifyDepictions();
|
||||
|
||||
/**
|
||||
* Clears previous selections
|
||||
*/
|
||||
void clearPreviousSelection();
|
||||
|
||||
LiveData<List<DepictedItem>> getDepictedItems();
|
||||
|
||||
/**
|
||||
* Update the depictions
|
||||
*/
|
||||
void updateDepictions(Media media);
|
||||
|
||||
/**
|
||||
* Attaches view and media
|
||||
*/
|
||||
void onAttachViewWithMedia(@NonNull View view, Media media);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,21 @@
|
|||
package fr.free.nrw.commons.upload.depicts;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
|
|
@ -18,7 +24,11 @@ import butterknife.OnClick;
|
|||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.jakewharton.rxbinding2.view.RxView;
|
||||
import com.jakewharton.rxbinding2.widget.RxTextView;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.contributions.ContributionsFragment;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.media.MediaDetailFragment;
|
||||
import fr.free.nrw.commons.ui.PasteSensitiveTextInputEditText;
|
||||
import fr.free.nrw.commons.upload.UploadActivity;
|
||||
import fr.free.nrw.commons.upload.UploadBaseFragment;
|
||||
|
|
@ -27,8 +37,10 @@ import fr.free.nrw.commons.utils.DialogUtil;
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import kotlin.Unit;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
|
@ -52,11 +64,26 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
RecyclerView depictsRecyclerView;
|
||||
@BindView(R.id.tooltip)
|
||||
ImageView tooltip;
|
||||
@BindView(R.id.depicts_next)
|
||||
Button btnNext;
|
||||
@BindView(R.id.depicts_previous)
|
||||
Button btnPrevious;
|
||||
@Inject
|
||||
@Named("default_preferences")
|
||||
public
|
||||
JsonKvStore applicationKvStore;
|
||||
|
||||
@Inject
|
||||
DepictsContract.UserActionListener presenter;
|
||||
private UploadDepictsAdapter adapter;
|
||||
private Disposable subscribe;
|
||||
private Media media;
|
||||
private ProgressDialog progressDialog;
|
||||
/**
|
||||
* Determines each encounter of edit depicts
|
||||
*/
|
||||
private int count;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public android.view.View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
|
|
@ -67,7 +94,13 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
@Override
|
||||
public void onViewCreated(@NonNull android.view.View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
ButterKnife.bind(this, view);
|
||||
Bundle bundle = getArguments();
|
||||
if (bundle != null) {
|
||||
media = bundle.getParcelable("Existing_Depicts");
|
||||
}
|
||||
|
||||
init();
|
||||
presenter.getDepictedItems().observe(getViewLifecycleOwner(), this::setDepictsList);
|
||||
}
|
||||
|
|
@ -76,13 +109,27 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
* Initialize presenter and views
|
||||
*/
|
||||
private void init() {
|
||||
depictsTitle.setText(getString(R.string.step_count, callback.getIndexInViewFlipper(this) + 1,
|
||||
callback.getTotalNumberOfSteps(), getString(R.string.depicts_step_title)));
|
||||
|
||||
if (media == null) {
|
||||
depictsTitle
|
||||
.setText(getString(R.string.step_count, callback.getIndexInViewFlipper(this) + 1,
|
||||
callback.getTotalNumberOfSteps(), getString(R.string.depicts_step_title)));
|
||||
} else {
|
||||
depictsTitle.setText(R.string.edit_depictions);
|
||||
depictsSubTitle.setVisibility(View.GONE);
|
||||
btnNext.setText(R.string.menu_save_categories);
|
||||
btnPrevious.setText(R.string.menu_cancel_upload);
|
||||
}
|
||||
|
||||
setDepictsSubTitle();
|
||||
tooltip.setOnClickListener(v -> DialogUtil
|
||||
.showAlertDialog(getActivity(), getString(R.string.depicts_step_title),
|
||||
getString(R.string.depicts_tooltip), getString(android.R.string.ok), null, true));
|
||||
presenter.onAttachView(this);
|
||||
if (media == null) {
|
||||
presenter.onAttachView(this);
|
||||
} else {
|
||||
presenter.onAttachViewWithMedia(this, media);
|
||||
}
|
||||
initRecyclerView();
|
||||
addTextChangeListenerToSearchBox();
|
||||
}
|
||||
|
|
@ -105,10 +152,17 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
* Initialise recyclerView and set adapter
|
||||
*/
|
||||
private void initRecyclerView() {
|
||||
adapter = new UploadDepictsAdapter(item -> {
|
||||
presenter.onDepictItemClicked(item);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
if (media == null) {
|
||||
adapter = new UploadDepictsAdapter(categoryItem -> {
|
||||
presenter.onDepictItemClicked(categoryItem);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
} else {
|
||||
adapter = new UploadDepictsAdapter(item -> {
|
||||
presenter.onDepictItemClicked(item);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
depictsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
depictsRecyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
|
@ -133,19 +187,28 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
|
||||
@Override
|
||||
public void noDepictionSelected() {
|
||||
DialogUtil.showAlertDialog(getActivity(),
|
||||
getString(R.string.no_depictions_selected),
|
||||
getString(R.string.no_depictions_selected_warning_desc),
|
||||
getString(R.string.continue_message),
|
||||
getString(R.string.cancel),
|
||||
this::goToNextScreen,
|
||||
null
|
||||
);
|
||||
if (media == null) {
|
||||
DialogUtil.showAlertDialog(getActivity(),
|
||||
getString(R.string.no_depictions_selected),
|
||||
getString(R.string.no_depictions_selected_warning_desc),
|
||||
getString(R.string.continue_message),
|
||||
getString(R.string.cancel),
|
||||
this::goToNextScreen,
|
||||
null
|
||||
);
|
||||
} else {
|
||||
Toast.makeText(requireContext(), getString(R.string.no_depictions_selected),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
presenter.clearPreviousSelection();
|
||||
updateDepicts();
|
||||
goBackToPreviousScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
media = null;
|
||||
presenter.onDetachView();
|
||||
subscribe.dispose();
|
||||
}
|
||||
|
|
@ -166,18 +229,98 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
|
||||
@Override
|
||||
public void setDepictsList(List<DepictedItem> depictedItemList) {
|
||||
adapter.setItems(depictedItemList);
|
||||
|
||||
if (applicationKvStore.getBoolean("first_edit_depict")) {
|
||||
count = 1;
|
||||
applicationKvStore.putBoolean("first_edit_depict", false);
|
||||
adapter.setItems(depictedItemList);
|
||||
} else {
|
||||
if ((count == 0) && (!depictedItemList.isEmpty())) {
|
||||
adapter.setItems(null);
|
||||
count = 1;
|
||||
} else {
|
||||
adapter.setItems(depictedItemList);
|
||||
}
|
||||
}
|
||||
depictsRecyclerView.smoothScrollToPosition(0);
|
||||
}
|
||||
|
||||
@OnClick(R.id.depicts_next)
|
||||
public void onNextButtonClicked() {
|
||||
presenter.verifyDepictions();
|
||||
/**
|
||||
* Returns required context
|
||||
*/
|
||||
@Override
|
||||
public Context getFragmentContext(){
|
||||
return requireContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns to previous fragment
|
||||
*/
|
||||
@Override
|
||||
public void goBackToPreviousScreen() {
|
||||
getFragmentManager().popBackStack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets existing depictions IDs from media
|
||||
*/
|
||||
@Override
|
||||
public List<String> getExistingDepictions(){
|
||||
return (media == null) ? null : media.getDepictionIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the progress dialog
|
||||
*/
|
||||
@Override
|
||||
public void showProgressDialog() {
|
||||
progressDialog = new ProgressDialog(requireContext());
|
||||
progressDialog.setMessage(getString(R.string.please_wait));
|
||||
progressDialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the progress dialog
|
||||
*/
|
||||
@Override
|
||||
public void dismissProgressDialog() {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the depicts
|
||||
*/
|
||||
@Override
|
||||
public void updateDepicts() {
|
||||
final MediaDetailFragment mediaDetailFragment = (MediaDetailFragment) getParentFragment();
|
||||
assert mediaDetailFragment != null;
|
||||
mediaDetailFragment.onResume();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the calling fragment by media nullability and act accordingly
|
||||
*/
|
||||
@OnClick(R.id.depicts_next)
|
||||
public void onNextButtonClicked() {
|
||||
if(media != null){
|
||||
presenter.updateDepictions(media);
|
||||
} else {
|
||||
presenter.verifyDepictions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the calling fragment by media nullability and act accordingly
|
||||
*/
|
||||
@OnClick(R.id.depicts_previous)
|
||||
public void onPreviousButtonClicked() {
|
||||
callback.onPreviousButtonClicked(callback.getIndexInViewFlipper(this));
|
||||
if(media != null){
|
||||
presenter.clearPreviousSelection();
|
||||
updateDepicts();
|
||||
goBackToPreviousScreen();
|
||||
} else {
|
||||
callback.onPreviousButtonClicked(callback.getIndexInViewFlipper(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -200,4 +343,63 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
private void searchForDepictions(final String query) {
|
||||
presenter.searchForDepictions(query);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Hides the action bar while opening editing fragment
|
||||
*/
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (media != null) {
|
||||
depictsSearch.setOnKeyListener((v, keyCode, event) -> {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
depictsSearch.clearFocus();
|
||||
presenter.clearPreviousSelection();
|
||||
updateDepicts();
|
||||
goBackToPreviousScreen();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
Objects.requireNonNull(getView()).setFocusableInTouchMode(true);
|
||||
getView().requestFocus();
|
||||
getView().setOnKeyListener((v, keyCode, event) -> {
|
||||
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
presenter.clearPreviousSelection();
|
||||
updateDepicts();
|
||||
goBackToPreviousScreen();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
Objects.requireNonNull(
|
||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
||||
.hide();
|
||||
|
||||
if (getParentFragment().getParentFragment().getParentFragment()
|
||||
instanceof ContributionsFragment) {
|
||||
((ContributionsFragment) (getParentFragment()
|
||||
.getParentFragment().getParentFragment())).nearbyNotificationCardView
|
||||
.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the action bar while closing editing fragment
|
||||
*/
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
if (media != null) {
|
||||
Objects.requireNonNull(
|
||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
package fr.free.nrw.commons.upload.depicts
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.di.CommonsApplicationModule
|
||||
import fr.free.nrw.commons.repository.UploadRepository
|
||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
|
||||
import fr.free.nrw.commons.wikidata.WikidataDisambiguationItems
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Scheduler
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.processors.PublishProcessor
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import java.lang.reflect.Proxy
|
||||
import java.util.*
|
||||
|
|
@ -35,8 +39,11 @@ class DepictsPresenter @Inject constructor(
|
|||
private val compositeDisposable: CompositeDisposable = CompositeDisposable()
|
||||
private val searchTerm: PublishProcessor<String> = PublishProcessor.create()
|
||||
private val depictedItems: MutableLiveData<List<DepictedItem>> = MutableLiveData()
|
||||
private var media: Media? = null
|
||||
@Inject
|
||||
lateinit var depictsDao: DepictsDao;
|
||||
lateinit var depictsDao: DepictsDao
|
||||
@Inject
|
||||
lateinit var depictsHelper: DepictEditHelper
|
||||
|
||||
override fun onAttachView(view: DepictsContract.View) {
|
||||
this.view = view
|
||||
|
|
@ -71,16 +78,37 @@ class DepictsPresenter @Inject constructor(
|
|||
if (querystring.isEmpty()) {
|
||||
recentDepictedItemList = getRecentDepictedItems();
|
||||
}
|
||||
return repository.searchAllEntities(querystring)
|
||||
.subscribeOn(ioScheduler)
|
||||
.map { repository.selectedDepictions + it + recentDepictedItemList }
|
||||
.map { it.filterNot { item -> WikidataDisambiguationItems.isDisambiguationItem(item.instanceOfs) } }
|
||||
.map { it.distinctBy(DepictedItem::id) }
|
||||
}
|
||||
|
||||
if (media == null) {
|
||||
return repository.searchAllEntities(querystring)
|
||||
.subscribeOn(ioScheduler)
|
||||
.map { repository.selectedDepictions + it + recentDepictedItemList }
|
||||
.map { it.filterNot { item -> WikidataDisambiguationItems.isDisambiguationItem(item.instanceOfs) } }
|
||||
.map { it.distinctBy(DepictedItem::id) }
|
||||
|
||||
} else {
|
||||
return Flowable.zip(repository.getDepictions(repository.selectedExistingDepictions)
|
||||
.map { list -> list.map {
|
||||
DepictedItem(it.name, it.description, it.imageUrl, it.instanceOfs,
|
||||
it.commonsCategories, true, it.id)
|
||||
}
|
||||
},
|
||||
repository.searchAllEntities(querystring),
|
||||
{ it1, it2 ->
|
||||
it1 + it2
|
||||
}
|
||||
)
|
||||
.subscribeOn(ioScheduler)
|
||||
.map { repository.selectedDepictions + it + recentDepictedItemList }
|
||||
.map { it.filterNot { item -> WikidataDisambiguationItems.isDisambiguationItem(item.instanceOfs) } }
|
||||
.map { it.distinctBy(DepictedItem::id) }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetachView() {
|
||||
view = DUMMY
|
||||
media = null
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +130,7 @@ class DepictsPresenter @Inject constructor(
|
|||
private fun selectNewDepictions(toSelect: List<DepictedItem>) {
|
||||
toSelect.forEach {
|
||||
it.isSelected = true
|
||||
repository.onDepictItemClicked(it)
|
||||
repository.onDepictItemClicked(it, media)
|
||||
}
|
||||
|
||||
// Add the new selections to the list of depicted items so that the selections appear
|
||||
|
|
@ -113,12 +141,16 @@ class DepictsPresenter @Inject constructor(
|
|||
?.let { depictedItems.value = it }
|
||||
}
|
||||
|
||||
override fun clearPreviousSelection() {
|
||||
repository.cleanup()
|
||||
}
|
||||
|
||||
override fun onPreviousButtonClicked() {
|
||||
view.goToPreviousScreen()
|
||||
}
|
||||
|
||||
override fun onDepictItemClicked(depictedItem: DepictedItem) {
|
||||
repository.onDepictItemClicked(depictedItem)
|
||||
repository.onDepictItemClicked(depictedItem, media)
|
||||
}
|
||||
|
||||
override fun getDepictedItems(): LiveData<List<DepictedItem>> {
|
||||
|
|
@ -149,6 +181,76 @@ class DepictsPresenter @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selected depicts and send them for posting to the server
|
||||
* and saves them in local storage
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
override fun updateDepictions(media: Media) {
|
||||
if (repository.selectedDepictions.isNotEmpty()
|
||||
|| repository.selectedExistingDepictions.size != view.existingDepictions.size
|
||||
) {
|
||||
view.showProgressDialog()
|
||||
val selectedDepictions: MutableList<String> =
|
||||
(repository.selectedDepictions.map { it.id }.toMutableList()
|
||||
+ repository.selectedExistingDepictions).toMutableList()
|
||||
|
||||
if (selectedDepictions.isNotEmpty()) {
|
||||
if (::depictsDao.isInitialized) {
|
||||
//save all the selected Depicted item in room Database
|
||||
depictsDao.savingDepictsInRoomDataBase(repository.selectedDepictions)
|
||||
}
|
||||
|
||||
compositeDisposable.add(
|
||||
depictsHelper.makeDepictionEdit(view.fragmentContext, media, selectedDepictions)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
media.depictionIds = selectedDepictions
|
||||
repository.cleanup()
|
||||
view.dismissProgressDialog()
|
||||
view.updateDepicts()
|
||||
view.goBackToPreviousScreen()
|
||||
})
|
||||
{
|
||||
Timber.e(
|
||||
"Failed to update depictions"
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
} else {
|
||||
repository.cleanup()
|
||||
view.noDepictionSelected()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachViewWithMedia(view: DepictsContract.View, media: Media) {
|
||||
this.view = view
|
||||
this.media = media
|
||||
repository.selectedExistingDepictions = view.existingDepictions
|
||||
compositeDisposable.add(
|
||||
searchTerm
|
||||
.observeOn(mainThreadScheduler)
|
||||
.doOnNext { view.showProgress(true) }
|
||||
.switchMap(::searchResultsWithTerm)
|
||||
.observeOn(mainThreadScheduler)
|
||||
.subscribe(
|
||||
{ (results, term) ->
|
||||
view.showProgress(false)
|
||||
view.showError(results.isEmpty() && term.isNotEmpty())
|
||||
depictedItems.value = results
|
||||
},
|
||||
{ t: Throwable? ->
|
||||
view.showProgress(false)
|
||||
view.showError(true)
|
||||
Timber.e(t)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the depicts from DepictsRoomdataBase
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package fr.free.nrw.commons.wikidata;
|
||||
|
||||
import static fr.free.nrw.commons.media.MediaClientKt.PAGE_ID_PREFIX;
|
||||
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
|
||||
import static fr.free.nrw.commons.media.MediaClientKt.PAGE_ID_PREFIX;
|
||||
|
||||
import fr.free.nrw.commons.upload.UploadResult;
|
||||
import fr.free.nrw.commons.upload.WikiBaseInterface;
|
||||
|
|
@ -35,6 +35,20 @@ public class WikiBaseClient {
|
|||
.map(response -> (response.getSuccessVal() == 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the server call for posting new depicts
|
||||
*
|
||||
* @param filename name of the file
|
||||
* @param data data of the depicts to be uploaded
|
||||
* @return Observable<Boolean>
|
||||
*/
|
||||
public Observable<Boolean> postEditEntityByFilename(final String filename, final String data) {
|
||||
return csrfToken()
|
||||
.switchMap(editToken -> wikiBaseInterface.postEditEntityByFilename(filename,
|
||||
editToken, data)
|
||||
.map(response -> (response.getSuccessVal() == 1)));
|
||||
}
|
||||
|
||||
public Observable<Long> getFileEntityId(UploadResult uploadResult) {
|
||||
return wikiBaseInterface.getFileEntityId(uploadResult.createCanonicalFileName())
|
||||
.map(response -> (long) (response.query().pages().get(0).pageId()));
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import fr.free.nrw.commons.upload.WikidataPlace;
|
|||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -73,11 +72,12 @@ public class WikidataEditService {
|
|||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private Observable<Boolean> addDepictsProperty(final String fileEntityId,
|
||||
final WikidataItem depictedItem) {
|
||||
final List<String> depictedItems) {
|
||||
|
||||
final EditClaim data = editClaim(
|
||||
ConfigUtils.isBetaFlavour() ? "Q10" // Wikipedia:Sandbox (Q10)
|
||||
: depictedItem.getId()
|
||||
ConfigUtils.isBetaFlavour() ? Collections.singletonList("Q10")
|
||||
// Wikipedia:Sandbox (Q10)
|
||||
: depictedItems
|
||||
);
|
||||
|
||||
return wikiBaseClient.postEditEntity(PAGE_ID_PREFIX + fileEntityId, gson.toJson(data))
|
||||
|
|
@ -95,8 +95,42 @@ public class WikidataEditService {
|
|||
.subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
private EditClaim editClaim(final String entityId) {
|
||||
return EditClaim.from(entityId, WikidataProperties.DEPICTS.getPropertyName());
|
||||
/**
|
||||
* Takes depicts ID as a parameter and create a uploadable data with the Id
|
||||
* and send the data for POST operation
|
||||
*
|
||||
* @param filename name of the file
|
||||
* @param depictedItems ID of the selected depict item
|
||||
* @return Observable<Boolean>
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
public Observable<Boolean> updateDepictsProperty(final String filename,
|
||||
final List<String> depictedItems) {
|
||||
|
||||
final EditClaim data = editClaim(
|
||||
ConfigUtils.isBetaFlavour() ? Collections.singletonList("Q10")
|
||||
// Wikipedia:Sandbox (Q10)
|
||||
: depictedItems
|
||||
);
|
||||
|
||||
return wikiBaseClient.postEditEntityByFilename(filename,
|
||||
gson.toJson(data))
|
||||
.doOnNext(success -> {
|
||||
if (success) {
|
||||
Timber.d("DEPICTS property was set successfully for %s", filename);
|
||||
} else {
|
||||
Timber.d("Unable to set DEPICTS property for %s", filename);
|
||||
}
|
||||
})
|
||||
.doOnError(throwable -> {
|
||||
Timber.e(throwable, "Error occurred while setting DEPICTS property");
|
||||
ViewUtil.showLongToast(context, throwable.toString());
|
||||
})
|
||||
.subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
private EditClaim editClaim(final List<String> entityIds) {
|
||||
return EditClaim.from(entityIds, WikidataProperties.DEPICTS.getPropertyName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -209,7 +243,12 @@ public class WikidataEditService {
|
|||
}
|
||||
|
||||
private Observable<Boolean> depictionEdits(Contribution contribution, Long fileEntityId) {
|
||||
return Observable.fromIterable(contribution.getDepictedItems())
|
||||
.concatMap(wikidataItem -> addDepictsProperty(fileEntityId.toString(), wikidataItem));
|
||||
final List<String> depictIDs = new ArrayList<>();
|
||||
for (final WikidataItem wikidataItem :
|
||||
contribution.getDepictedItems()) {
|
||||
depictIDs.add(wikidataItem.getId());
|
||||
}
|
||||
return addDepictsProperty(fileEntityId.toString(), depictIDs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue