#3780 Create media using a combination of Entities & MwQueryResult (#3786)

* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchDepictionsRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace UploadCategoryDepictionsRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - update BaseAdapter to be easier to use

* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchImagesRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace SearchCategoriesRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace NotificationRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace UploadDepictsRenderer

* #3468 Switch from RvRenderer to AdapterDelegates - replace PlaceRenderer

* #3756 Convert SearchDepictionsFragment to use Pagination - convert SearchDepictionsFragment

* #3756 Convert SearchDepictionsFragment to use Pagination - fix presenter unit tests now that view is not nullable - fix Category prefix imports

* #3756 Convert SearchDepictionsFragment to use Pagination - test DataSource related classes

* #3756 Convert SearchDepictionsFragment to use Pagination - reset rx scheduler - ignore failing test

* #3760 Convert SearchCategoriesFragment to use Pagination - extract functionality of pagination to base classes - add category pagination

* #3772 Convert SearchImagesFragment to use Pagination  - convert SearchImagesFragment - tidy up showing the empty view - make search fragments show snackbar with appropriate text

* #3772 Convert SearchImagesFragment to use Pagination  - allow viewpager to load more data

* #3760 remove test that got re-added by merge

* #3760 remove duplicate dependency

* #3772 fix compilation

* #3780 Create media using a combination of Entities & MwQueryResult - construct media with an entity - move fields from media down to contribution - move dynamic fields outside of media - remove unused constructors - remove all unnecessary fetching of captions/descriptions - bump database version

* #3808 Construct media objects that depict an item id correctly - use generator to construct media for DepictedImages

* #3780 Create media using a combination of Entities & MwQueryResult - update wikicode to align with expected behaviour

* #3780 Create media using a combination of Entities & MwQueryResult - replace old site of thumbnail title with most relevant caption
This commit is contained in:
Seán Mac Gillicuddy 2020-06-25 08:20:01 +01:00 committed by GitHub
parent bf4b7e2efc
commit 4b22583b60
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 803 additions and 1532 deletions

View file

@ -1,17 +1,18 @@
package fr.free.nrw.commons.contributions;
import android.net.Uri;
import android.os.Parcel;
import androidx.annotation.Nullable;
import androidx.room.Entity;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.upload.UploadMediaDetail;
import fr.free.nrw.commons.upload.UploadItem;
import fr.free.nrw.commons.upload.UploadMediaDetail;
import fr.free.nrw.commons.upload.WikidataPlace;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Entity(tableName = "contribution")
@ -34,24 +35,23 @@ public class Contribution extends Media {
*/
private List<DepictedItem> depictedItems = new ArrayList<>();
private String mimeType;
/**
* This hasmap stores the list of multilingual captions, where key of the HashMap is the language
* and value is the caption in the corresponding language Ex: key = "en", value: "<caption in
* short in English>" key = "de" , value: "<caption in german>"
*/
private HashMap<String, String> captions = new HashMap<>();
@Nullable
private Uri localUri;
private long dataLength;
private Date dateCreated;
public Contribution() {
}
public Contribution(final UploadItem item, final SessionManager sessionManager,
final List<DepictedItem> depictedItems, final List<String> categories) {
super(item.getMediaUri(),
super(
item.getFileName(),
UploadMediaDetail.formatList(item.getUploadMediaDetails()),
UploadMediaDetail.formatCaptions(item.getUploadMediaDetails()),
UploadMediaDetail.formatDescriptions(item.getUploadMediaDetails()),
sessionManager.getAuthorName(),
categories);
captions = new HashMap<>(UploadMediaDetail.formatCaptions(item.getUploadMediaDetails()));
localUri = item.getMediaUri();
decimalCoords = item.getGpsCoords().getDecimalCoords();
dateCreatedSource = "";
this.depictedItems = depictedItems;
@ -117,24 +117,6 @@ public class Contribution extends Media {
this.mimeType = mimeType;
}
/**
* Captions are a feature part of Structured data. They are meant to store short, multilingual
* descriptions about files This is a replacement of the previously used titles for images (titles
* were not multilingual) Also now captions replace the previous convention of using title for
* filename
* <p>
* key of the HashMap is the language and value is the caption in the corresponding language
* <p>
* returns list of captions stored in hashmap
*/
public HashMap<String, String> getCaptions() {
return captions;
}
public void setCaptions(HashMap<String, String> captions) {
this.captions = captions;
}
@Override
public int describeContents() {
return 0;
@ -147,7 +129,6 @@ public class Contribution extends Media {
dest.writeLong(transferred);
dest.writeString(decimalCoords);
dest.writeString(dateCreatedSource);
dest.writeSerializable(captions);
}
/**
@ -156,13 +137,7 @@ public class Contribution extends Media {
* @param state
*/
public Contribution(Media media, int state) {
super(media.getPageId(),
media.getLocalUri(), media.getThumbUrl(), media.getImageUrl(), media.getFilename(),
media.getDescription(),
media.getDiscussion(),
media.getDataLength(), media.getDateCreated(), media.getDateUploaded(),
media.getLicense(), media.getLicenseUrl(), media.getCreator(), media.getCategories(),
media.isRequestedDeletion(), media.getCoordinates());
super(media);
this.state = state;
}
@ -172,7 +147,6 @@ public class Contribution extends Media {
transferred = in.readLong();
decimalCoords = in.readString();
dateCreatedSource = in.readString();
captions = (HashMap<String, String>) in.readSerializable();
}
public static final Creator<Contribution> CREATOR = new Creator<Contribution>() {
@ -187,34 +161,60 @@ public class Contribution extends Media {
}
};
/**
* Equals implementation of Contributions that compares all parameters for checking equality
*/
@Nullable
public Uri getLocalUri() {
return localUri;
}
public void setLocalUri(@Nullable Uri localUri) {
this.localUri = localUri;
}
public long getDataLength() {
return dataLength;
}
public void setDataLength(long dataLength) {
this.dataLength = dataLength;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Contribution)) {
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
final Contribution that = (Contribution) o;
return getState() == that.getState() && getTransferred() == that.getTransferred() && Objects
.equals(getDecimalCoords(), that.getDecimalCoords()) && Objects
.equals(getDateCreatedSource(), that.getDateCreatedSource()) && Objects
.equals(getWikidataPlace(), that.getWikidataPlace()) && Objects
.equals(getDepictedItems(), that.getDepictedItems()) && Objects
.equals(getMimeType(), that.getMimeType()) && Objects
.equals(getCaptions(), that.getCaptions());
return state == that.state &&
transferred == that.transferred &&
dataLength == that.dataLength &&
Objects.equals(decimalCoords, that.decimalCoords) &&
Objects.equals(dateCreatedSource, that.dateCreatedSource) &&
Objects.equals(wikidataPlace, that.wikidataPlace) &&
Objects.equals(depictedItems, that.depictedItems) &&
Objects.equals(mimeType, that.mimeType) &&
Objects.equals(localUri, that.localUri) &&
Objects.equals(dateCreated, that.dateCreated);
}
/**
* Hash code implementation of contributions that considers all parameters for calculating hash.
*/
@Override
public int hashCode() {
return Objects
.hash(getState(), getTransferred(), getDecimalCoords(), getDateCreatedSource(),
getWikidataPlace(), getDepictedItems(), getMimeType(), getCaptions());
.hash(super.hashCode(), state, transferred, decimalCoords, dateCreatedSource,
wikidataPlace,
depictedItems, mimeType, localUri, dataLength, dateCreated);
}
}

View file

@ -62,9 +62,7 @@ class ContributionBoundaryCallback @Inject constructor(
}
}
.subscribeOn(ioThreadScheduler)
.subscribe(
::saveContributionsToDB
) { error: Throwable ->
.subscribe(::saveContributionsToDB) { error: Throwable ->
Timber.e(
"Failed to fetch contributions: %s",
error.message

View file

@ -1,12 +1,9 @@
package fr.free.nrw.commons.contributions;
import static fr.free.nrw.commons.depictions.Media.DepictedImagesFragment.PAGE_ID_PREFIX;
import android.net.Uri;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
@ -24,8 +21,6 @@ import fr.free.nrw.commons.media.MediaClient;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import org.wikipedia.dataclient.WikiSite;
import timber.log.Timber;
public class ContributionViewHolder extends RecyclerView.ViewHolder {
@ -65,8 +60,8 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
public void init(final int position, final Contribution contribution) {
this.contribution = contribution;
fetchAndDisplayCaption(contribution);
this.position = position;
titleView.setText(contribution.getMostRelevantCaption());
final String imageSource = chooseImageSource(contribution.getThumbUrl(),
contribution.getLocalUri());
if (!TextUtils.isEmpty(imageSource)) {
@ -116,37 +111,6 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
}
}
/**
* In contributions first we show the title for the image stored in cache, then we fetch captions
* associated with the image and replace title on the thumbnail with caption
*
* @param contribution
*/
private void fetchAndDisplayCaption(final Contribution contribution) {
if ((contribution.getState() != Contribution.STATE_COMPLETED)) {
titleView.setText(contribution.getDisplayTitle());
} else {
final String pageId = contribution.getPageId();
if (pageId != null) {
Timber.d("Fetching caption for %s", contribution.getFilename());
final String wikibaseMediaId = PAGE_ID_PREFIX
+ pageId; // 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)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber -> {
if (!subscriber.trim().equals(MediaClient.NO_CAPTION)) {
titleView.setText(subscriber);
} else {
titleView.setText(contribution.getDisplayTitle());
}
}));
} else {
titleView.setText(contribution.getDisplayTitle());
}
}
}
/**
* Checks if a media exists on the corresponding Wikipedia article Currently the check is made for
* the device's current language Wikipedia

View file

@ -1,9 +1,6 @@
package fr.free.nrw.commons.contributions;
import java.util.List;
import fr.free.nrw.commons.BasePresenter;
import fr.free.nrw.commons.Media;
/**
* The contract for Contributions View & Presenter
@ -21,8 +18,5 @@ public class ContributionsContract {
void deleteUpload(Contribution contribution);
void updateContribution(Contribution contribution);
void fetchMediaDetails(Contribution contribution);
}
}

View file

@ -46,9 +46,8 @@ public class ContributionsListAdapter extends
* Initializes the view holder with contribution data
*/
@Override
public void onBindViewHolder(@NonNull final ContributionViewHolder holder, final int position) {
final Contribution contribution = getItem(position);
holder.init(position, contribution);
public void onBindViewHolder(@NonNull ContributionViewHolder holder, int position) {
holder.init(position, getItem(position));
}
Contribution getContributionForPosition(final int position) {

View file

@ -1,30 +1,10 @@
package fr.free.nrw.commons.contributions;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.MediaDataExtractor;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.MediaDataExtractor;
import fr.free.nrw.commons.contributions.ContributionsContract.UserActionListener;
import fr.free.nrw.commons.di.CommonsApplicationModule;
import fr.free.nrw.commons.mwapi.UserClient;
import fr.free.nrw.commons.utils.NetworkUtils;
import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber;
import javax.inject.Inject;
import javax.inject.Named;
@ -77,24 +57,4 @@ public class ContributionsPresenter implements UserActionListener {
.subscribeOn(ioThreadScheduler)
.subscribe());
}
@Override
public void updateContribution(Contribution contribution) {
compositeDisposable.add(repository
.updateContribution(contribution)
.subscribeOn(ioThreadScheduler)
.subscribe());
}
@Override
public void fetchMediaDetails(Contribution contribution) {
compositeDisposable.add(mediaDataExtractor
.getMediaFromFileName(contribution.getFilename())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(media -> {
contribution.setThumbUrl(media.getThumbUrl());
updateContribution(contribution);
}));
}
}