#3222 Merge master into Structured Data branch, fix conflicts - review fixes

This commit is contained in:
Sean Mac Gillicuddy 2020-03-23 11:30:02 +00:00
parent 1404bb0da6
commit 895b343f81
17 changed files with 163 additions and 205 deletions

View file

@ -1,20 +1,18 @@
package fr.free.nrw.commons; package fr.free.nrw.commons;
import static fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX;
import androidx.core.text.HtmlCompat; import androidx.core.text.HtmlCompat;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import fr.free.nrw.commons.media.MediaClient;
import io.reactivex.Single;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jetbrains.annotations.NotNull;
import fr.free.nrw.commons.media.MediaClient;
import io.reactivex.Single;
import timber.log.Timber; import timber.log.Timber;
/** /**
@ -25,10 +23,15 @@ import timber.log.Timber;
*/ */
@Singleton @Singleton
public class MediaDataExtractor { public class MediaDataExtractor {
private final MediaClient mediaClient;
private static final int LABEL_BEGIN_INDEX = 3;
private static final int LABEL_END_OFFSET = 3;
private static final int ID_BEGIN_INDEX = 1;
private static final int ID_END_OFFSET = 1;
private final MediaClient mediaClient;
@Inject @Inject
public MediaDataExtractor(MediaClient mediaClient) { public MediaDataExtractor(final MediaClient mediaClient) {
this.mediaClient = mediaClient; this.mediaClient = mediaClient;
} }
@ -38,31 +41,35 @@ public class MediaDataExtractor {
* @param filename for which the details are to be fetched * @param filename for which the details are to be fetched
* @return full Media object with all details including deletion status and talk page * @return full Media object with all details including deletion status and talk page
*/ */
public Single<Media> fetchMediaDetails(String filename, String pageId) { public Single<Media> fetchMediaDetails(final String filename, final String pageId) {
Single<Media> mediaSingle = getMediaFromFileName(filename); return Single.zip(getMediaFromFileName(filename),
Single<Boolean> pageExistsSingle = mediaClient.checkPageExistsUsingTitle("Commons:Deletion_requests/" + filename); mediaClient.checkPageExistsUsingTitle("Commons:Deletion_requests/" + filename),
Single<String> discussionSingle = getDiscussion(filename); getDiscussion(filename),
Single<String> captionSingle = getCaption("M"+pageId); getCaption(PAGE_ID_PREFIX + pageId),
Single<JsonObject> depictionSingle = getDepictions(filename); getDepictions(filename),
return Single.zip(mediaSingle, pageExistsSingle, discussionSingle, captionSingle, depictionSingle, (media, deletionStatus, discussion, caption, depiction) -> { this::combineToMedia);
media.setDiscussion(discussion);
media.setCaption(caption);
media.setDepiction(formatDepictions(depiction));
if (deletionStatus) {
media.setRequestedDeletion();
}
return media;
});
} }
/** @NotNull
private Media combineToMedia(final Media media, final Boolean deletionStatus, final String discussion,
final String caption, final JsonObject depiction) {
media.setDiscussion(discussion);
media.setCaption(caption);
media.setDepiction(formatDepictions(depiction));
if (deletionStatus) {
media.setRequestedDeletion();
}
return media;
}
/**
* Obtains captions using filename * Obtains captions using filename
* @param wikibaseIdentifier * @param wikibaseIdentifier
* *
* @return caption for the image in user's locale * @return caption for the image in user's locale
* Ex: "a nice painting" (english locale) and "No Caption" in case the caption is not available for the image * Ex: "a nice painting" (english locale) and "No Caption" in case the caption is not available for the image
*/ */
private Single<String> getCaption(String wikibaseIdentifier) { private Single<String> getCaption(final String wikibaseIdentifier) {
return mediaClient.getCaptionByWikibaseIdentifier(wikibaseIdentifier); return mediaClient.getCaptionByWikibaseIdentifier(wikibaseIdentifier);
} }
@ -72,27 +79,23 @@ public class MediaDataExtractor {
* @return List containing map for depictions, the map has two keys, * @return List containing map for depictions, the map has two keys,
* first key is for the label and second is for the url of the item * first key is for the label and second is for the url of the item
*/ */
private ArrayList<Map<String, String>> formatDepictions(JsonObject mediaResponse) { private ArrayList<Map<String, String>> formatDepictions(final JsonObject mediaResponse) {
try { try {
JsonArray depictionArray = (JsonArray) mediaResponse.get("Depiction"); final JsonArray depictionArray = (JsonArray) mediaResponse.get("Depiction");
ArrayList<Map<String, String>> depictedItemList = new ArrayList<>(); final ArrayList<Map<String, String>> depictedItemList = new ArrayList<>();
try { for (int i = 0; i <depictionArray.size() ; i++) {
for (int i = 0; i <depictionArray.size() ; i++) { final JsonObject depictedItem = (JsonObject) depictionArray.get(i);
JsonObject depictedItem = (JsonObject) depictionArray.get(i); final Map <String, String> depictedObject = new HashMap<>();
Map <String, String> depictedObject = new HashMap<>(); final String label = depictedItem.get("label").toString();
String label = depictedItem.get("label").toString(); final String id = depictedItem.get("id").toString();
String id = depictedItem.get("id").toString(); final String transformedLabel = label.substring(LABEL_BEGIN_INDEX, label.length()- LABEL_END_OFFSET);
String transformedLabel = label.substring(3, label.length()-3); final String transformedId = id.substring(ID_BEGIN_INDEX,id.length() - ID_END_OFFSET);
String transformedId = id.substring(1,id.length() - 1); depictedObject.put("label", transformedLabel); //remove the additional characters obtained in label and ID object to extract the relevant string (since the string also contains extra quites that are not required)
depictedObject.put("label", transformedLabel); //remove the additional characters obtained in label and ID object to extract the relevant string (since the string also contains extra quites that are not required) depictedObject.put("id", transformedId);
depictedObject.put("id", transformedId); depictedItemList.add(depictedObject);
depictedItemList.add(depictedObject);
}
return depictedItemList;
} catch (NullPointerException e) {
return new ArrayList<>();
} }
} catch (ClassCastException c) { return depictedItemList;
} catch (final ClassCastException | NullPointerException ignore) {
return new ArrayList<>(); return new ArrayList<>();
} }
} }
@ -102,13 +105,9 @@ public class MediaDataExtractor {
* @param filename the filename we will return the caption for * @param filename the filename we will return the caption for
* @return a map containing caption and depictions (empty string in the map if no caption/depictions) * @return a map containing caption and depictions (empty string in the map if no caption/depictions)
*/ */
private Single<JsonObject> getDepictions(String filename) { private Single<JsonObject> getDepictions(final String filename) {
return mediaClient.getCaptionAndDepictions(filename) return mediaClient.getCaptionAndDepictions(filename)
.map(mediaResponse -> { .doOnError(throwable -> Timber.e(throwable, "error while fetching depictions"));
return mediaResponse;
}).doOnError(throwable -> {
Timber.e(throwable+ "error while fetching depictions");
});
} }
/** /**
@ -116,7 +115,7 @@ public class MediaDataExtractor {
* @param filename Eg. File:Test.jpg * @param filename Eg. File:Test.jpg
* @return return data rich Media object * @return return data rich Media object
*/ */
public Single<Media> getMediaFromFileName(String filename) { public Single<Media> getMediaFromFileName(final String filename) {
return mediaClient.getMedia(filename); return mediaClient.getMedia(filename);
} }
@ -125,7 +124,7 @@ public class MediaDataExtractor {
* @param filename * @param filename
* @return * @return
*/ */
private Single<String> getDiscussion(String filename) { private Single<String> getDiscussion(final String filename) {
return mediaClient.getPageHtml(filename.replace("File", "File talk")) return mediaClient.getPageHtml(filename.replace("File", "File talk"))
.map(discussion -> HtmlCompat.fromHtml(discussion, HtmlCompat.FROM_HTML_MODE_LEGACY).toString()) .map(discussion -> HtmlCompat.fromHtml(discussion, HtmlCompat.FROM_HTML_MODE_LEGACY).toString())
.onErrorReturn(throwable -> { .onErrorReturn(throwable -> {

View file

@ -1,5 +1,9 @@
package fr.free.nrw.commons.category; package fr.free.nrw.commons.category;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -12,15 +16,7 @@ import android.widget.ListAdapter;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import dagger.android.support.DaggerFragment; import dagger.android.support.DaggerFragment;
@ -33,11 +29,12 @@ import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber; import timber.log.Timber;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
/** /**
* Displays images for a particular category with load more on scrolling incorporated * Displays images for a particular category with load more on scrolling incorporated
*/ */
@ -261,7 +258,7 @@ public class CategoryImagesListFragment extends DaggerFragment {
isLoading = false; isLoading = false;
statusTextView.setVisibility(GONE); statusTextView.setVisibility(GONE);
for (Media m : collection) { for (Media m : collection) {
replaceTitlesWithCaptions("M"+m.getPageId(), mediaSize++); replaceTitlesWithCaptions(PAGE_ID_PREFIX + m.getPageId(), mediaSize++);
} }
} }

View file

@ -1,5 +1,7 @@
package fr.free.nrw.commons.contributions; package fr.free.nrw.commons.contributions;
import static fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.net.Uri; import android.net.Uri;
@ -117,7 +119,7 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
titleView.setText(contribution.getDisplayTitle()); titleView.setText(contribution.getDisplayTitle());
} else { } else {
Timber.d("Fetching caption for %s", contribution.getFilename()); Timber.d("Fetching caption for %s", contribution.getFilename());
String wikibaseMediaId = "M"+contribution.getPageId(); // Create Wikibase media id from the page id. Example media id: M80618155 for https://commons.wikimedia.org/wiki/File:Tantanmen.jpeg with has the pageid 80618155 String wikibaseMediaId = PAGE_ID_PREFIX + contribution.getPageId(); // Create Wikibase media id from the page id. Example media id: M80618155 for https://commons.wikimedia.org/wiki/File:Tantanmen.jpeg with has the pageid 80618155
compositeDisposable.add(mediaClient.getCaptionByWikibaseIdentifier(wikibaseMediaId) compositeDisposable.add(mediaClient.getCaptionByWikibaseIdentifier(wikibaseMediaId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View file

@ -12,6 +12,9 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* This class supplies converters to write/read types to/from the database.
*/
public class Converters { public class Converters {
public static Gson getGson() { public static Gson getGson() {

View file

@ -57,7 +57,7 @@ public class GridViewAdapter extends ArrayAdapter {
data = new ArrayList<>(); data = new ArrayList<>();
return false; return false;
} }
if (data.size() <= 0) { if (data.size() == 0) {
return false; return false;
} }
String fileName = data.get(0).getFilename(); String fileName = data.get(0).getFilename();

View file

@ -34,7 +34,7 @@ public interface DepictedImagesContract {
/** /**
* Seat caption to the image at the given position * Seat caption to the image at the given position
*/ */
void handleLabelforImage(String s, int position); void handleLabelforImage(String caption, int position);
/** /**
* Display snackbar * Display snackbar

View file

@ -1,5 +1,8 @@
package fr.free.nrw.commons.depictions.Media; package fr.free.nrw.commons.depictions.Media;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -11,26 +14,20 @@ import android.widget.ListAdapter;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.List;
import javax.inject.Inject;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import dagger.android.support.DaggerFragment; import dagger.android.support.DaggerFragment;
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.depictions.WikidataItemDetailsActivity;
import fr.free.nrw.commons.depictions.GridViewAdapter; import fr.free.nrw.commons.depictions.GridViewAdapter;
import fr.free.nrw.commons.depictions.WikidataItemDetailsActivity;
import fr.free.nrw.commons.utils.NetworkUtils; import fr.free.nrw.commons.utils.NetworkUtils;
import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtil;
import java.util.List;
import static android.view.View.GONE; import javax.inject.Inject;
import static android.view.View.VISIBLE; import timber.log.Timber;
/** /**
* Fragment for showing image list after selected an item from SearchActivity In Explore * Fragment for showing image list after selected an item from SearchActivity In Explore
@ -38,6 +35,7 @@ import static android.view.View.VISIBLE;
public class DepictedImagesFragment extends DaggerFragment implements DepictedImagesContract.View { public class DepictedImagesFragment extends DaggerFragment implements DepictedImagesContract.View {
public static final String PAGE_ID_PREFIX = "M";
@BindView(R.id.statusMessage) @BindView(R.id.statusMessage)
TextView statusTextView; TextView statusTextView;
@BindView(R.id.loadingImagesProgressBar) @BindView(R.id.loadingImagesProgressBar)
@ -87,7 +85,9 @@ public class DepictedImagesFragment extends DaggerFragment implements DepictedIm
presenter.initList(entityId); presenter.initList(entityId);
if (!NetworkUtils.isInternetConnectionEstablished(getContext())) { if (!NetworkUtils.isInternetConnectionEstablished(getContext())) {
handleNoInternet(); handleNoInternet();
} else presenter.initList(entityId); } else {
presenter.initList(entityId);
}
} }
/** /**
@ -150,9 +150,9 @@ public class DepictedImagesFragment extends DaggerFragment implements DepictedIm
* Seat caption to the image at the given position * Seat caption to the image at the given position
*/ */
@Override @Override
public void handleLabelforImage(String s, int position) { public void handleLabelforImage(String caption, int position) {
if (!s.trim().equals(getString(R.string.detail_caption_empty))) { if (!caption.trim().equals(getString(R.string.detail_caption_empty))) {
gridAdapter.getItem(position).setThumbnailTitle(s); gridAdapter.getItem(position).setThumbnailTitle(caption);
gridAdapter.notifyDataSetChanged(); gridAdapter.notifyDataSetChanged();
} }
} }
@ -250,15 +250,15 @@ public class DepictedImagesFragment extends DaggerFragment implements DepictedIm
try { try {
((WikidataItemDetailsActivity) getContext()).viewPagerNotifyDataSetChanged(); ((WikidataItemDetailsActivity) getContext()).viewPagerNotifyDataSetChanged();
} catch (Exception e) { } catch (RuntimeException e) {
e.printStackTrace(); Timber.e(e);
} }
} }
progressBar.setVisibility(GONE); progressBar.setVisibility(GONE);
isLoading = false; isLoading = false;
statusTextView.setVisibility(GONE); statusTextView.setVisibility(GONE);
for (Media m : collection) { for (Media media : collection) {
presenter.replaceTitlesWithCaptions("M"+m.getPageId(), mediaSize++); presenter.replaceTitlesWithCaptions(PAGE_ID_PREFIX +media.getPageId(), mediaSize++);
} }
} }
} }

View file

@ -1,26 +1,22 @@
package fr.free.nrw.commons.depictions.Media; package fr.free.nrw.commons.depictions.Media;
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.explore.depictions.DepictsClient; import fr.free.nrw.commons.explore.depictions.DepictsClient;
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.media.MediaClient; import fr.free.nrw.commons.media.MediaClient;
import io.reactivex.Scheduler; import io.reactivex.Scheduler;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber; import timber.log.Timber;
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
/** /**
* Presenter for DepictedImagesFragment * Presenter for DepictedImagesFragment
*/ */
@ -31,7 +27,6 @@ public class DepictedImagesPresenter implements DepictedImagesContract.UserActio
DepictedImagesContract.View.class.getClassLoader(), DepictedImagesContract.View.class.getClassLoader(),
new Class[]{DepictedImagesContract.View.class}, new Class[]{DepictedImagesContract.View.class},
(proxy, method, methodArgs) -> null); (proxy, method, methodArgs) -> null);
private static int TIMEOUT_SECONDS = 15;
DepictsClient depictsClient; DepictsClient depictsClient;
MediaClient mediaClient; MediaClient mediaClient;
@Named("default_preferences") @Named("default_preferences")
@ -76,10 +71,9 @@ public class DepictedImagesPresenter implements DepictedImagesContract.UserActio
view.setLoadingStatus(true); view.setLoadingStatus(true);
view.progressBarVisible(true); view.progressBarVisible(true);
view.setIsLastPage(false); view.setIsLastPage(false);
compositeDisposable.add(depictsClient.fetchImagesForDepictedItem(entityId, 25, 0) compositeDisposable.add(depictsClient.fetchImagesForDepictedItem(entityId, 0)
.subscribeOn(ioScheduler) .subscribeOn(ioScheduler)
.observeOn(mainThreadScheduler) .observeOn(mainThreadScheduler)
.timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.subscribe(this::handleSuccess, this::handleError)); .subscribe(this::handleSuccess, this::handleError));
} }
@ -90,10 +84,9 @@ public class DepictedImagesPresenter implements DepictedImagesContract.UserActio
@Override @Override
public void fetchMoreImages() { public void fetchMoreImages() {
view.progressBarVisible(true); view.progressBarVisible(true);
compositeDisposable.add(depictsClient.fetchImagesForDepictedItem(entityId, 25, queryList.size()) compositeDisposable.add(depictsClient.fetchImagesForDepictedItem(entityId, queryList.size())
.subscribeOn(ioScheduler) .subscribeOn(ioScheduler)
.observeOn(mainThreadScheduler) .observeOn(mainThreadScheduler)
.timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.subscribe(this::handlePaginationSuccess, this::handleError)); .subscribe(this::handlePaginationSuccess, this::handleError));
} }
@ -150,9 +143,8 @@ public class DepictedImagesPresenter implements DepictedImagesContract.UserActio
compositeDisposable.add(mediaClient.getCaptionByWikibaseIdentifier(wikibaseIdentifier) compositeDisposable.add(mediaClient.getCaptionByWikibaseIdentifier(wikibaseIdentifier)
.subscribeOn(ioScheduler) .subscribeOn(ioScheduler)
.observeOn(mainThreadScheduler) .observeOn(mainThreadScheduler)
.timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) .subscribe(caption -> {
.subscribe(subscriber -> { view.handleLabelforImage(caption, position);
view.handleLabelforImage(subscriber, position);
})); }));
} }

View file

@ -1,14 +1,7 @@
package fr.free.nrw.commons.depictions.SubClass; package fr.free.nrw.commons.depictions.SubClass;
import java.io.IOException; import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
import java.lang.reflect.Proxy; import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import fr.free.nrw.commons.explore.depictions.DepictsClient; import fr.free.nrw.commons.explore.depictions.DepictsClient;
import fr.free.nrw.commons.explore.recentsearches.RecentSearch; import fr.free.nrw.commons.explore.recentsearches.RecentSearch;
@ -16,14 +9,17 @@ import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao;
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient; import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem; import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import io.reactivex.Scheduler; import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers; import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber; import timber.log.Timber;
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
/** /**
* Presenter for parent classes and child classes of Depicted items in Explore * Presenter for parent classes and child classes of Depicted items in Explore
*/ */
@ -155,13 +151,8 @@ public class SubDepictionListPresenter implements SubDepictionListContract.UserA
*/ */
private void handleError(Throwable throwable) { private void handleError(Throwable throwable) {
Timber.e(throwable, "Error occurred while loading queried depictions"); Timber.e(throwable, "Error occurred while loading queried depictions");
try { view.initErrorView();
view.initErrorView(); view.showSnackbar();
view.showSnackbar();
} catch (Exception e) {
e.printStackTrace();
}
} }
} }

View file

@ -33,7 +33,7 @@ import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
public class WikidataItemDetailsActivity extends NavigationBaseActivity implements MediaDetailPagerFragment.MediaDetailProvider, AdapterView.OnItemClickListener { public class WikidataItemDetailsActivity extends NavigationBaseActivity implements MediaDetailPagerFragment.MediaDetailProvider, AdapterView.OnItemClickListener {
private FragmentManager supportFragmentManager; private FragmentManager supportFragmentManager;
private DepictedImagesFragment depictionImagesListFragment; private DepictedImagesFragment depictionImagesListFragment;
private MediaDetailPagerFragment mediaDetails; private MediaDetailPagerFragment mediaDetailPagerFragment;
/** /**
* Name of the depicted item * Name of the depicted item
* Ex: Rabbit * Ex: Rabbit
@ -78,8 +78,8 @@ public class WikidataItemDetailsActivity extends NavigationBaseActivity implemen
* The viewpager will notified that number of items have changed. * The viewpager will notified that number of items have changed.
*/ */
public void viewPagerNotifyDataSetChanged() { public void viewPagerNotifyDataSetChanged() {
if (mediaDetails!=null){ if (mediaDetailPagerFragment !=null){
mediaDetails.notifyDataSetChanged(); mediaDetailPagerFragment.notifyDataSetChanged();
} }
} }
@ -129,18 +129,18 @@ public class WikidataItemDetailsActivity extends NavigationBaseActivity implemen
tabLayout.setVisibility(View.GONE); tabLayout.setVisibility(View.GONE);
viewPager.setVisibility(View.GONE); viewPager.setVisibility(View.GONE);
mediaContainer.setVisibility(View.VISIBLE); mediaContainer.setVisibility(View.VISIBLE);
if (mediaDetails == null || !mediaDetails.isVisible()) { if (mediaDetailPagerFragment == null || !mediaDetailPagerFragment.isVisible()) {
// set isFeaturedImage true for featured images, to include author field on media detail // set isFeaturedImage true for featured images, to include author field on media detail
mediaDetails = new MediaDetailPagerFragment(false, true); mediaDetailPagerFragment = new MediaDetailPagerFragment(false, true);
FragmentManager supportFragmentManager = getSupportFragmentManager(); FragmentManager supportFragmentManager = getSupportFragmentManager();
supportFragmentManager supportFragmentManager
.beginTransaction() .beginTransaction()
.replace(R.id.mediaContainer, mediaDetails) .replace(R.id.mediaContainer, mediaDetailPagerFragment)
.addToBackStack(null) .addToBackStack(null)
.commit(); .commit();
supportFragmentManager.executePendingTransactions(); supportFragmentManager.executePendingTransactions();
} }
mediaDetails.showImage(position); mediaDetailPagerFragment.showImage(position);
forceInitBackButton(); forceInitBackButton();
} }

View file

@ -54,7 +54,6 @@ public class NetworkingModule {
public static final String NAMED_COMMONS_WIKI_SITE = "commons-wikisite"; public static final String NAMED_COMMONS_WIKI_SITE = "commons-wikisite";
private static final String NAMED_WIKI_DATA_WIKI_SITE = "wikidata-wikisite"; private static final String NAMED_WIKI_DATA_WIKI_SITE = "wikidata-wikisite";
private static final String NAMED_COMMONS_WIKI = "commonswiki";
public static final String NAMED_COMMONS_CSRF = "commons-csrf"; public static final String NAMED_COMMONS_CSRF = "commons-csrf";
@ -138,12 +137,6 @@ public class NetworkingModule {
return new WikiSite(BuildConfig.WIKIDATA_URL); return new WikiSite(BuildConfig.WIKIDATA_URL);
} }
@Provides
@Singleton
@Named(NAMED_COMMONS_WIKI)
public WikiSite provideCommonsWiki() {
return new WikiSite(BuildConfig.COMMONS_URL);
}
/** /**
* Gson objects are very heavy. The app should ideally be using just one instance of it instead of creating new instances everywhere. * Gson objects are very heavy. The app should ideally be using just one instance of it instead of creating new instances everywhere.
@ -230,7 +223,7 @@ public class NetworkingModule {
@Provides @Provides
@Singleton @Singleton
public MediaDetailInterface providesMediaDetailInterface(@Named(NAMED_COMMONS_WIKI) WikiSite commonsWikisite) { public MediaDetailInterface providesMediaDetailInterface(@Named(NAMED_COMMONS_WIKI_SITE) WikiSite commonsWikisite) {
return ServiceFactory.get(commonsWikisite, BuildConfig.COMMONS_URL, MediaDetailInterface.class); return ServiceFactory.get(commonsWikisite, BuildConfig.COMMONS_URL, MediaDetailInterface.class);
} }

View file

@ -105,7 +105,7 @@ public class DepictsClient {
/** /**
* @return list of images for a particular depict entity * @return list of images for a particular depict entity
*/ */
public Observable<List<Media>> fetchImagesForDepictedItem(String query, int limit, int sroffset) { public Observable<List<Media>> fetchImagesForDepictedItem(String query, int sroffset) {
return mediaInterface.fetchImagesForDepictedItem("haswbstatement:" + BuildConfig.DEPICTS_PROPERTY + "=" + query, String.valueOf(sroffset)) return mediaInterface.fetchImagesForDepictedItem("haswbstatement:" + BuildConfig.DEPICTS_PROPERTY + "=" + query, String.valueOf(sroffset))
.map(mwQueryResponse -> { .map(mwQueryResponse -> {
List<Media> mediaList = new ArrayList<>(); List<Media> mediaList = new ArrayList<>();

View file

@ -1,27 +1,24 @@
package fr.free.nrw.commons.explore.depictions; package fr.free.nrw.commons.explore.depictions;
import java.lang.reflect.Proxy; import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
import java.util.ArrayList; import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.explore.recentsearches.RecentSearch; import fr.free.nrw.commons.explore.recentsearches.RecentSearch;
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao; import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao;
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem; import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import io.reactivex.Scheduler; import io.reactivex.Scheduler;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber; import timber.log.Timber;
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
/** /**
* The presenter class for SearchDepictionsFragment * The presenter class for SearchDepictionsFragment
*/ */
@ -105,13 +102,8 @@ public class SearchDepictionsFragmentPresenter extends CommonsDaggerSupportFragm
*/ */
private void handleError(Throwable throwable) { private void handleError(Throwable throwable) {
Timber.e(throwable, "Error occurred while loading queried depictions"); Timber.e(throwable, "Error occurred while loading queried depictions");
try { view.initErrorView();
view.initErrorView(); view.showSnackbar();
view.showSnackbar();
} catch (Exception e) {
e.printStackTrace();
}
} }
/** /**

View file

@ -41,6 +41,7 @@ import timber.log.Timber;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX;
/** /**
* Displays the image search screen. * Displays the image search screen.
@ -205,7 +206,7 @@ public class SearchImageFragment extends CommonsDaggerSupportFragment {
imagesAdapter.notifyDataSetChanged(); imagesAdapter.notifyDataSetChanged();
((SearchActivity)getContext()).viewPagerNotifyDataSetChanged(); ((SearchActivity)getContext()).viewPagerNotifyDataSetChanged();
for (Media m : mediaList) { for (Media m : mediaList) {
replaceTitlesWithCaptions("M"+m.getPageId(), mediaSize++); replaceTitlesWithCaptions(PAGE_ID_PREFIX + m.getPageId(), mediaSize++);
} }
} }
} }
@ -215,13 +216,13 @@ public class SearchImageFragment extends CommonsDaggerSupportFragment {
* When captions are retrieved they replace title * When captions are retrieved they replace title
*/ */
public void replaceTitlesWithCaptions(String wikibaseIdentifier, int i) { public void replaceTitlesWithCaptions(String wikibaseIdentifier, int position) {
compositeDisposable.add(mediaClient.getCaptionByWikibaseIdentifier(wikibaseIdentifier) compositeDisposable.add(mediaClient.getCaptionByWikibaseIdentifier(wikibaseIdentifier)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) .timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.subscribe(subscriber -> { .subscribe(subscriber -> {
handleLabelforImage(subscriber, i); handleLabelforImage(subscriber, position);
})); }));
} }

View file

@ -2,36 +2,28 @@ package fr.free.nrw.commons.media;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.google.gson.internal.LinkedTreeMap; import com.google.gson.internal.LinkedTreeMap;
import java.util.Date;
import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.utils.CommonsDateUtil; import fr.free.nrw.commons.utils.CommonsDateUtil;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Single; import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
import timber.log.Timber; import timber.log.Timber;
/** /**
@ -186,26 +178,23 @@ public class MediaClient {
public Single<String> getCaptionByWikibaseIdentifier(String wikibaseIdentifier) { public Single<String> getCaptionByWikibaseIdentifier(String wikibaseIdentifier) {
return mediaDetailInterface.getCaptionForImage(Locale.getDefault().getLanguage(), wikibaseIdentifier) return mediaDetailInterface.getCaptionForImage(Locale.getDefault().getLanguage(), wikibaseIdentifier)
.map(mediaDetailResponse -> { .map(mediaDetailResponse -> {
if (mediaDetailResponse != null && mediaDetailResponse.getSuccess() != null && mediaDetailResponse.getSuccess() == 1 && mediaDetailResponse.getEntities() != null) { if (isSuccess(mediaDetailResponse)) {
Map<String, CommonsWikibaseItem> entities = mediaDetailResponse.getEntities(); for (CommonsWikibaseItem wikibaseItem : mediaDetailResponse.getEntities().values()) {
try { for (Caption caption : wikibaseItem.getLabels().values()) {
Map.Entry<String, CommonsWikibaseItem> entry = entities.entrySet().iterator().next();
CommonsWikibaseItem commonsWikibaseItem = entry.getValue();
Map<String, Caption> labels = commonsWikibaseItem.getLabels();
Map.Entry<String, Caption> captionEntry = labels.entrySet().iterator().next();
Caption caption = captionEntry.getValue();
return caption.getValue(); return caption.getValue();
}
} catch (Exception e) {
return NO_CAPTION;
} }
} }
return NO_CAPTION; return NO_CAPTION;
}) })
.singleOrError(); .singleOrError();
} }
private boolean isSuccess(MediaDetailResponse response) {
return response != null && response.getSuccess() != null
&& response.getSuccess() == 1 && response.getEntities() != null;
}
/** /**
* Fetches Structured data from API * Fetches Structured data from API
* *
@ -214,9 +203,7 @@ public class MediaClient {
*/ */
public Single<JsonObject> getCaptionAndDepictions(String filename) { public Single<JsonObject> getCaptionAndDepictions(String filename) {
return mediaDetailInterface.fetchStructuredDataByFilename(Locale.getDefault().getLanguage(), filename) return mediaDetailInterface.fetchStructuredDataByFilename(Locale.getDefault().getLanguage(), filename)
.map(mediaDetailResponse -> { .map(this::fetchCaptionandDepictionsFromMediaDetailResponse)
return fetchCaptionandDepictionsFromMediaDetailResponse(mediaDetailResponse);
})
.singleOrError(); .singleOrError();
} }
@ -228,7 +215,7 @@ public class MediaClient {
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
private JsonObject fetchCaptionandDepictionsFromMediaDetailResponse(MediaDetailResponse mediaDetailResponse) { private JsonObject fetchCaptionandDepictionsFromMediaDetailResponse(MediaDetailResponse mediaDetailResponse) {
JsonObject mediaDetails = new JsonObject(); JsonObject mediaDetails = new JsonObject();
if (mediaDetailResponse != null && mediaDetailResponse.getSuccess() != null && mediaDetailResponse.getSuccess() == 1 && mediaDetailResponse.getEntities() != null) { if (isSuccess(mediaDetailResponse)) {
Map<String, CommonsWikibaseItem> entities = mediaDetailResponse.getEntities(); Map<String, CommonsWikibaseItem> entities = mediaDetailResponse.getEntities();
try { try {
Map.Entry<String, CommonsWikibaseItem> entry = entities.entrySet().iterator().next(); Map.Entry<String, CommonsWikibaseItem> entry = entities.entrySet().iterator().next();
@ -247,7 +234,6 @@ public class MediaClient {
try { try {
LinkedTreeMap statements = (LinkedTreeMap) commonsWikibaseItem.getStatements(); LinkedTreeMap statements = (LinkedTreeMap) commonsWikibaseItem.getStatements();
ArrayList<LinkedTreeMap> depictsItemList = (ArrayList<LinkedTreeMap>) statements.get(BuildConfig.DEPICTS_PROPERTY); ArrayList<LinkedTreeMap> depictsItemList = (ArrayList<LinkedTreeMap>) statements.get(BuildConfig.DEPICTS_PROPERTY);
String depictions = null;
JsonArray jsonArray = new JsonArray(); JsonArray jsonArray = new JsonArray();
for (int i = 0; i < depictsItemList.size(); i++) { for (int i = 0; i < depictsItemList.size(); i++) {
LinkedTreeMap depictedItem = depictsItemList.get(i); LinkedTreeMap depictedItem = depictsItemList.get(i);
@ -268,7 +254,6 @@ public class MediaClient {
} catch (Exception e) { } catch (Exception e) {
JsonElement jsonElement = new JsonPrimitive(NO_CAPTION); JsonElement jsonElement = new JsonPrimitive(NO_CAPTION);
mediaDetails.add("Caption", jsonElement); mediaDetails.add("Caption", jsonElement);
jsonElement = null;
jsonElement = new JsonPrimitive(NO_DEPICTION); jsonElement = new JsonPrimitive(NO_DEPICTION);
mediaDetails.add("Depiction", jsonElement); mediaDetails.add("Depiction", jsonElement);
} }

View file

@ -1,5 +1,7 @@
package fr.free.nrw.commons.wikidata; package fr.free.nrw.commons.wikidata;
import static fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -198,7 +200,7 @@ public class WikidataEditService {
String data = jsonData.toString(); String data = jsonData.toString();
Observable.defer((Callable<ObservableSource<Boolean>>) () -> Observable.defer((Callable<ObservableSource<Boolean>>) () ->
wikiBaseClient.postEditEntity("M" + fileEntityId, data)) wikiBaseClient.postEditEntity(PAGE_ID_PREFIX + fileEntityId, data))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(success -> { .subscribe(success -> {

View file

@ -55,7 +55,8 @@ class DepictedImagesPresenterTest {
@Test @Test
fun initList() { fun initList() {
Mockito.`when`(depictsClient?.fetchImagesForDepictedItem(ArgumentMatchers.anyString(), ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())).thenReturn(testObservable) Mockito.`when`(depictsClient?.fetchImagesForDepictedItem(ArgumentMatchers.anyString(),
ArgumentMatchers.anyInt())).thenReturn(testObservable)
depictedImagesPresenter?.initList("rabbit") depictedImagesPresenter?.initList("rabbit")
depictedImagesPresenter?.handleSuccess(mediaList) depictedImagesPresenter?.handleSuccess(mediaList)
verify(view)?.handleSuccess(mediaList) verify(view)?.handleSuccess(mediaList)