mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Fetch and use thumbnail across the app (#2906)
This commit is contained in:
parent
17d69cde02
commit
37e9eae314
18 changed files with 161 additions and 260 deletions
|
|
@ -42,6 +42,7 @@ public class Media implements Parcelable {
|
|||
|
||||
// Primary metadata fields
|
||||
protected Uri localUri;
|
||||
private String thumbUrl;
|
||||
protected String imageUrl;
|
||||
protected String filename;
|
||||
protected String description; // monolingual description on input...
|
||||
|
|
@ -93,6 +94,7 @@ public class Media implements Parcelable {
|
|||
long dataLength, Date dateCreated, Date dateUploaded, String creator) {
|
||||
this();
|
||||
this.localUri = localUri;
|
||||
this.thumbUrl = imageUrl;
|
||||
this.imageUrl = imageUrl;
|
||||
this.filename = filename;
|
||||
this.description = description;
|
||||
|
|
@ -107,6 +109,7 @@ public class Media implements Parcelable {
|
|||
@SuppressWarnings("unchecked")
|
||||
public Media(Parcel in) {
|
||||
localUri = in.readParcelable(Uri.class.getClassLoader());
|
||||
thumbUrl = in.readString();
|
||||
imageUrl = in.readString();
|
||||
filename = in.readString();
|
||||
description = in.readString();
|
||||
|
|
@ -124,6 +127,67 @@ public class Media implements Parcelable {
|
|||
descriptions = in.readHashMap(ClassLoader.getSystemClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creating Media object from MWQueryPage.
|
||||
* Earlier only basic details were set for the media object but going forward,
|
||||
* a full media object(with categories, descriptions, coordinates etc) can be constructed using this method
|
||||
*
|
||||
* @param page response from the API
|
||||
* @return Media object
|
||||
*/
|
||||
@Nullable
|
||||
public static Media from(MwQueryPage page) {
|
||||
ImageInfo imageInfo = page.imageInfo();
|
||||
if (imageInfo == null) {
|
||||
return null;
|
||||
}
|
||||
ExtMetadata metadata = imageInfo.getMetadata();
|
||||
if (metadata == null) {
|
||||
Media media = new Media(null, imageInfo.getOriginalUrl(),
|
||||
page.title(), "", 0, null, null, null);
|
||||
if (!StringUtils.isBlank(imageInfo.getThumbUrl())) {
|
||||
media.setThumbUrl(imageInfo.getThumbUrl());
|
||||
}
|
||||
return media;
|
||||
}
|
||||
|
||||
Media media = new Media(null,
|
||||
imageInfo.getOriginalUrl(),
|
||||
page.title(),
|
||||
"",
|
||||
0,
|
||||
safeParseDate(metadata.dateTimeOriginal().value()),
|
||||
safeParseDate(metadata.dateTime().value()),
|
||||
StringUtil.fromHtml(metadata.artist().value()).toString()
|
||||
);
|
||||
|
||||
if (!StringUtils.isBlank(imageInfo.getThumbUrl())) {
|
||||
media.setThumbUrl(imageInfo.getThumbUrl());
|
||||
}
|
||||
|
||||
String language = Locale.getDefault().getLanguage();
|
||||
if (StringUtils.isBlank(language)) {
|
||||
language = "default";
|
||||
}
|
||||
|
||||
media.setDescriptions(Collections.singletonMap(language, metadata.imageDescription().value()));
|
||||
media.setCategories(MediaDataExtractorUtil.extractCategoriesFromList(metadata.categories().value()));
|
||||
String latitude = metadata.gpsLatitude().value();
|
||||
String longitude = metadata.gpsLongitude().value();
|
||||
|
||||
if (!StringUtils.isBlank(latitude) && !StringUtils.isBlank(longitude)) {
|
||||
LatLng latLng = new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude), 0);
|
||||
media.setCoordinates(latLng);
|
||||
}
|
||||
|
||||
media.setLicenseInformation(metadata.licenseShortName().value(), metadata.licenseUrl().value());
|
||||
return media;
|
||||
}
|
||||
|
||||
public String getThumbUrl() {
|
||||
return thumbUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tag of media
|
||||
* @param key Media key
|
||||
|
|
@ -322,53 +386,8 @@ public class Media implements Parcelable {
|
|||
return license;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creating Media object from MWQueryPage.
|
||||
* Earlier only basic details were set for the media object but going forward,
|
||||
* a full media object(with categories, descriptions, coordinates etc) can be constructed using this method
|
||||
*
|
||||
* @param page response from the API
|
||||
* @return Media object
|
||||
*/
|
||||
@Nullable
|
||||
public static Media from(MwQueryPage page) {
|
||||
ImageInfo imageInfo = page.imageInfo();
|
||||
if (imageInfo == null) {
|
||||
return null;
|
||||
}
|
||||
ExtMetadata metadata = imageInfo.getMetadata();
|
||||
if (metadata == null) {
|
||||
return new Media(null, imageInfo.getOriginalUrl(),
|
||||
page.title(), "", 0, null, null, null);
|
||||
}
|
||||
|
||||
Media media = new Media(null,
|
||||
imageInfo.getOriginalUrl(),
|
||||
page.title(),
|
||||
"",
|
||||
0,
|
||||
safeParseDate(metadata.dateTimeOriginal().value()),
|
||||
safeParseDate(metadata.dateTime().value()),
|
||||
StringUtil.fromHtml(metadata.artist().value()).toString()
|
||||
);
|
||||
|
||||
String language = Locale.getDefault().getLanguage();
|
||||
if (StringUtils.isBlank(language)) {
|
||||
language = "default";
|
||||
}
|
||||
|
||||
media.setDescriptions(Collections.singletonMap(language, metadata.imageDescription().value()));
|
||||
media.setCategories(MediaDataExtractorUtil.extractCategoriesFromList(metadata.categories().value()));
|
||||
String latitude = metadata.gpsLatitude().value();
|
||||
String longitude = metadata.gpsLongitude().value();
|
||||
|
||||
if (!StringUtils.isBlank(latitude) && !StringUtils.isBlank(longitude)) {
|
||||
LatLng latLng = new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude), 0);
|
||||
media.setCoordinates(latLng);
|
||||
}
|
||||
|
||||
media.setLicenseInformation(metadata.licenseShortName().value(), metadata.licenseUrl().value());
|
||||
return media;
|
||||
public void setThumbUrl(String thumbUrl) {
|
||||
this.thumbUrl = thumbUrl;
|
||||
}
|
||||
|
||||
public String getLicenseUrl() {
|
||||
|
|
@ -482,6 +501,7 @@ public class Media implements Parcelable {
|
|||
@Override
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeParcelable(localUri, flags);
|
||||
parcel.writeString(thumbUrl);
|
||||
parcel.writeString(imageUrl);
|
||||
parcel.writeString(filename);
|
||||
parcel.writeString(description);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package fr.free.nrw.commons;
|
||||
|
||||
import android.text.Html;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
|
@ -36,7 +34,7 @@ public class MediaDataExtractor {
|
|||
* @return full Media object with all details including deletion status and talk page
|
||||
*/
|
||||
public Single<Media> fetchMediaDetails(String filename) {
|
||||
Single<Media> mediaSingle = okHttpJsonApiClient.getMedia(filename, false);
|
||||
Single<Media> mediaSingle = getMediaFromFileName(filename);
|
||||
Single<Boolean> pageExistsSingle = mediaWikiApi.pageExists("Commons:Deletion_requests/" + filename);
|
||||
Single<String> discussionSingle = getDiscussion(filename);
|
||||
return Single.zip(mediaSingle, pageExistsSingle, discussionSingle, (media, deletionStatus, discussion) -> {
|
||||
|
|
@ -48,6 +46,15 @@ public class MediaDataExtractor {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method can be used to fetch media for a given filename
|
||||
* @param filename Eg. File:Test.jpg
|
||||
* @return return data rich Media object
|
||||
*/
|
||||
public Single<Media> getMediaFromFileName(String filename) {
|
||||
return okHttpJsonApiClient.getMedia(filename, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch talk page from the MediaWiki API
|
||||
* @param filename
|
||||
|
|
|
|||
|
|
@ -1,123 +0,0 @@
|
|||
package fr.free.nrw.commons;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.LruCache;
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class MediaWikiImageView extends SimpleDraweeView {
|
||||
@Inject MediaWikiApi mwApi;
|
||||
@Inject LruCache<String, String> thumbnailUrlCache;
|
||||
|
||||
protected CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
public MediaWikiImageView(Context context) {
|
||||
this(context, null);
|
||||
init();
|
||||
}
|
||||
|
||||
public MediaWikiImageView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
init();
|
||||
}
|
||||
|
||||
public MediaWikiImageView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the media. Fetches its thumbnail if necessary.
|
||||
* @param media the new media
|
||||
*/
|
||||
public void setMedia(Media media) {
|
||||
if (media == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Disposable disposable = fetchMediaThumbnail(media)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(thumbnail -> {
|
||||
if (!StringUtils.isBlank(thumbnail)) {
|
||||
setImageUrl(thumbnail);
|
||||
}
|
||||
}, throwable -> Timber.e(throwable, "Error occurred while fetching thumbnail"));
|
||||
|
||||
compositeDisposable.add(disposable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
compositeDisposable.clear();
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes MediaWikiImageView.
|
||||
*/
|
||||
private void init() {
|
||||
ApplicationlessInjection
|
||||
.getInstance(getContext()
|
||||
.getApplicationContext())
|
||||
.getCommonsApplicationComponent()
|
||||
.inject(this);
|
||||
setHierarchy(GenericDraweeHierarchyBuilder
|
||||
.newInstance(getResources())
|
||||
.setPlaceholderImage(VectorDrawableCompat.create(getResources(),
|
||||
R.drawable.ic_image_black_24dp, getContext().getTheme()))
|
||||
.setFailureImage(VectorDrawableCompat.create(getResources(),
|
||||
R.drawable.ic_image_black_24dp, getContext().getTheme()))
|
||||
.build());
|
||||
}
|
||||
|
||||
//TODO: refactor the logic for thumbnails. ImageInfo API can be used to fetch thumbnail upfront
|
||||
|
||||
/**
|
||||
* Fetches media thumbnail from the server
|
||||
*
|
||||
* @param media
|
||||
* @return
|
||||
*/
|
||||
public Single<String> fetchMediaThumbnail(Media media) {
|
||||
if (media.getFilename() != null && thumbnailUrlCache.get(media.getFilename()) != null) {
|
||||
return Single.just(thumbnailUrlCache.get(media.getFilename()));
|
||||
}
|
||||
return mwApi.findThumbnailByFilename(media.getFilename())
|
||||
.map(result -> {
|
||||
if (TextUtils.isEmpty(result) && media.getLocalUri() != null) {
|
||||
return media.getLocalUri().toString();
|
||||
} else {
|
||||
thumbnailUrlCache.put(media.getFilename(), result);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the image from the URL.
|
||||
* @param url the URL of the image
|
||||
*/
|
||||
private void setImageUrl(@Nullable String url) {
|
||||
setImageURI(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -8,12 +8,13 @@ import android.view.ViewGroup;
|
|||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.MediaWikiImageView;
|
||||
import fr.free.nrw.commons.R;
|
||||
|
||||
/**
|
||||
|
|
@ -82,12 +83,12 @@ public class GridViewAdapter extends ArrayAdapter {
|
|||
}
|
||||
|
||||
Media item = data.get(position);
|
||||
MediaWikiImageView imageView = convertView.findViewById(R.id.categoryImageView);
|
||||
SimpleDraweeView imageView = convertView.findViewById(R.id.categoryImageView);
|
||||
TextView fileName = convertView.findViewById(R.id.categoryImageTitle);
|
||||
TextView author = convertView.findViewById(R.id.categoryImageAuthor);
|
||||
fileName.setText(item.getDisplayTitle());
|
||||
setAuthorView(item, author);
|
||||
imageView.setMedia(item);
|
||||
imageView.setImageURI(item.getThumbUrl());
|
||||
return convertView;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,23 +6,37 @@ import android.widget.LinearLayout;
|
|||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import fr.free.nrw.commons.MediaWikiImageView;
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.ViewHolder;
|
||||
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import timber.log.Timber;
|
||||
|
||||
class ContributionViewHolder implements ViewHolder<DisplayableContribution> {
|
||||
@BindView(R.id.contributionImage) MediaWikiImageView imageView;
|
||||
public class ContributionViewHolder implements ViewHolder<DisplayableContribution> {
|
||||
@BindView(R.id.contributionImage)
|
||||
SimpleDraweeView imageView;
|
||||
@BindView(R.id.contributionTitle) TextView titleView;
|
||||
@BindView(R.id.contributionState) TextView stateView;
|
||||
@BindView(R.id.contributionSequenceNumber) TextView seqNumView;
|
||||
@BindView(R.id.contributionProgress) ProgressBar progressView;
|
||||
@BindView(R.id.failed_image_options) LinearLayout failedImageOptions;
|
||||
|
||||
@Inject
|
||||
MediaDataExtractor mediaDataExtractor;
|
||||
|
||||
private DisplayableContribution contribution;
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
ContributionViewHolder(View parent) {
|
||||
ButterKnife.bind(this, parent);
|
||||
|
|
@ -30,8 +44,10 @@ class ContributionViewHolder implements ViewHolder<DisplayableContribution> {
|
|||
|
||||
@Override
|
||||
public void bindModel(Context context, DisplayableContribution contribution) {
|
||||
ApplicationlessInjection.getInstance(context)
|
||||
.getCommonsApplicationComponent().inject(this);
|
||||
this.contribution = contribution;
|
||||
imageView.setMedia(contribution);
|
||||
fetchAndDisplayThumbnail(contribution);
|
||||
titleView.setText(contribution.getDisplayTitle());
|
||||
|
||||
seqNumView.setText(String.valueOf(contribution.getPosition() + 1));
|
||||
|
|
@ -71,6 +87,26 @@ class ContributionViewHolder implements ViewHolder<DisplayableContribution> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method fetches the thumbnail url from file name
|
||||
* This can be removed once #2904 is in place and contribution contains all metadata beforehand
|
||||
* @param contribution
|
||||
*/
|
||||
private void fetchAndDisplayThumbnail(DisplayableContribution contribution) {
|
||||
Timber.d("Fetching thumbnail for %s", contribution.getFilename());
|
||||
Disposable disposable = mediaDataExtractor.getMediaFromFileName(contribution.getFilename())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(media -> {
|
||||
imageView.setImageURI(media.getThumbUrl());
|
||||
});
|
||||
compositeDisposable.add(disposable);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
compositeDisposable.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry upload when it is failed
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ class ContributionsListAdapter extends CursorAdapter {
|
|||
final ContributionViewHolder views = (ContributionViewHolder)view.getTag();
|
||||
final Contribution contribution = contributionDao.fromCursor(cursor);
|
||||
|
||||
Timber.d("Cursor position is %d", cursor.getPosition());
|
||||
DisplayableContribution displayableContribution = new DisplayableContribution(contribution,
|
||||
cursor.getPosition(),
|
||||
new DisplayableContribution.ContributionActions() {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import dagger.android.AndroidInjectionModule;
|
|||
import dagger.android.AndroidInjector;
|
||||
import dagger.android.support.AndroidSupportInjectionModule;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.MediaWikiImageView;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.contributions.ContributionViewHolder;
|
||||
import fr.free.nrw.commons.contributions.ContributionsSyncAdapter;
|
||||
import fr.free.nrw.commons.modifications.ModificationsSyncAdapter;
|
||||
import fr.free.nrw.commons.nearby.PlaceRenderer;
|
||||
|
|
@ -36,8 +36,6 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application
|
|||
|
||||
void inject(ModificationsSyncAdapter syncAdapter);
|
||||
|
||||
void inject(MediaWikiImageView mediaWikiImageView);
|
||||
|
||||
void inject(LoginActivity activity);
|
||||
|
||||
void inject(SettingsFragment fragment);
|
||||
|
|
@ -53,6 +51,8 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application
|
|||
|
||||
void inject(PicOfDayAppWidget picOfDayAppWidget);
|
||||
|
||||
void inject(ContributionViewHolder viewHolder);
|
||||
|
||||
@Component.Builder
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
interface Builder {
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.pedrogomez.renderers.Renderer;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.MediaWikiImageView;
|
||||
import fr.free.nrw.commons.R;
|
||||
|
||||
/**
|
||||
|
|
@ -19,8 +19,7 @@ import fr.free.nrw.commons.R;
|
|||
class SearchImagesRenderer extends Renderer<Media> {
|
||||
@BindView(R.id.categoryImageTitle) TextView tvImageName;
|
||||
@BindView(R.id.categoryImageAuthor) TextView categoryImageAuthor;
|
||||
@BindView(R.id.categoryImageView)
|
||||
MediaWikiImageView browseImage;
|
||||
@BindView(R.id.categoryImageView) SimpleDraweeView browseImage;
|
||||
|
||||
private final ImageClickedListener listener;
|
||||
|
||||
|
|
@ -52,7 +51,7 @@ class SearchImagesRenderer extends Renderer<Media> {
|
|||
public void render() {
|
||||
Media item = getContent();
|
||||
tvImageName.setText(item.getDisplayTitle());
|
||||
browseImage.setMedia(item);
|
||||
browseImage.setImageURI(item.getThumbUrl());
|
||||
setAuthorView(item, categoryImageAuthor);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@ import android.widget.Spinner;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.wikipedia.util.DateUtil;
|
||||
import org.wikipedia.util.StringUtil;
|
||||
|
|
@ -37,7 +42,6 @@ import butterknife.ButterKnife;
|
|||
import butterknife.OnClick;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import fr.free.nrw.commons.MediaWikiImageView;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.category.CategoryDetailsActivity;
|
||||
|
|
@ -52,12 +56,6 @@ import io.reactivex.Single;
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
|
|
@ -100,7 +98,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
private int initialListTop = 0;
|
||||
|
||||
@BindView(R.id.mediaDetailImage)
|
||||
MediaWikiImageView image;
|
||||
SimpleDraweeView image;
|
||||
@BindView(R.id.mediaDetailSpacer)
|
||||
MediaDetailSpacer spacer;
|
||||
@BindView(R.id.mediaDetailTitle)
|
||||
|
|
@ -265,7 +263,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
|
||||
private void displayMediaDetails() {
|
||||
//Always load image from Internet to allow viewing the desc, license, and cats
|
||||
image.setMedia(media);
|
||||
setupImageView();
|
||||
title.setText(media.getDisplayTitle());
|
||||
desc.setHtmlText(media.getDescription());
|
||||
license.setText(media.getLicense());
|
||||
|
|
@ -277,6 +275,20 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
compositeDisposable.add(disposable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses two image sources.
|
||||
* - low resolution thumbnail is shown initially
|
||||
* - when the high resolution image is available, it replaces the low resolution image
|
||||
*/
|
||||
private void setupImageView() {
|
||||
DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||
.setLowResImageRequest(ImageRequest.fromUri(media.getThumbUrl()))
|
||||
.setImageRequest(ImageRequest.fromUri(media.getImageUrl()))
|
||||
.setOldController(image.getController())
|
||||
.build();
|
||||
image.setController(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (layoutListener != null && getView() != null) {
|
||||
|
|
@ -297,6 +309,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
|
||||
private void setTextFields(Media media) {
|
||||
this.media = media;
|
||||
setupImageView();
|
||||
desc.setHtmlText(prettyDescription(media));
|
||||
license.setText(prettyLicense(media));
|
||||
coordinates.setText(prettyCoordinates(media));
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ import timber.log.Timber;
|
|||
* @author Addshore
|
||||
*/
|
||||
public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
||||
private static final String THUMB_SIZE = "640";
|
||||
private AbstractHttpClient httpClient;
|
||||
private CustomMwApi api;
|
||||
private CustomMwApi wikidataApi;
|
||||
|
|
@ -293,18 +292,6 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
|||
.getString("/api/edit/@result");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<String> findThumbnailByFilename(String filename) {
|
||||
return Single.fromCallable(() -> api.action("query")
|
||||
.param("format", "xml")
|
||||
.param("prop", "imageinfo")
|
||||
.param("iiprop", "url")
|
||||
.param("iiurlwidth", THUMB_SIZE)
|
||||
.param("titles", filename)
|
||||
.get()
|
||||
.getString("/api/query/pages/page/imageinfo/ii/@thumburl"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<String> parseWikicode(String source) {
|
||||
return Single.fromCallable(() -> api.action("flow-parsoid-utils")
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@ public interface MediaWikiApi {
|
|||
|
||||
Single<Boolean> pageExists(String pageName);
|
||||
|
||||
Single<String> findThumbnailByFilename(String filename);
|
||||
|
||||
List<String> getSubCategoryList(String categoryName);
|
||||
|
||||
List<String> getParentCategoryList(String categoryName);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import timber.log.Timber;
|
|||
*/
|
||||
@Singleton
|
||||
public class OkHttpJsonApiClient {
|
||||
private static final String THUMB_SIZE = "640";
|
||||
|
||||
public static final Type mapType = new TypeToken<Map<String, String>>() {
|
||||
}.getType();
|
||||
|
|
@ -274,6 +275,7 @@ public class OkHttpJsonApiClient {
|
|||
private HttpUrl.Builder appendMediaProperties(HttpUrl.Builder builder) {
|
||||
builder.addQueryParameter("prop", "imageinfo")
|
||||
.addQueryParameter("iiprop", "url|extmetadata")
|
||||
.addQueryParameter("iiurlwidth", THUMB_SIZE)
|
||||
.addQueryParameter("iiextmetadatafilter", "DateTime|Categories|GPSLatitude|GPSLongitude|ImageDescription|DateTimeOriginal|Artist|LicenseShortName|LicenseUrl");
|
||||
|
||||
String language = Locale.getDefault().getLanguage();
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* This class includes utilities for contribution list fragment indicators, such as number of
|
||||
* uploads, notification and nearby cards and their progress bar behind them.
|
||||
*/
|
||||
public class ContributionListViewUtils {
|
||||
|
||||
/**
|
||||
* Sets indicator and progress bar visibility according to 3 states, data is ready to display,
|
||||
* data still loading, both should be invisible because media details fragment is visible
|
||||
* @param indicator this can be numOfUploads text view, notification/nearby card views
|
||||
* @param progressBar this is the progress bar behind indicators, displays they are loading
|
||||
* @param isIndicatorReady is indicator fetched the information will be displayed
|
||||
* @param isBothInvisible true if contribution list fragment is not active (ie. Media Details Fragment is active)
|
||||
*/
|
||||
public static void setIndicatorVisibility(View indicator, View progressBar, boolean isIndicatorReady, boolean isBothInvisible) {
|
||||
if (indicator!=null && progressBar!=null) {
|
||||
if (isIndicatorReady) {
|
||||
// Indicator ready, display them
|
||||
indicator.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
} else {
|
||||
if (isBothInvisible) {
|
||||
// Media Details Fragment is visible, hide both
|
||||
indicator.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
} else {
|
||||
// Indicator is not ready, still loading
|
||||
indicator.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ public class PicOfDayAppWidget extends AppWidgetProvider {
|
|||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, viewIntent, 0);
|
||||
views.setOnClickPendingIntent(R.id.appwidget_image, pendingIntent);
|
||||
|
||||
loadImageFromUrl(response.getImageUrl(), context, views, appWidgetManager, appWidgetId);
|
||||
loadImageFromUrl(response.getThumbUrl(), context, views, appWidgetManager, appWidgetId);
|
||||
}
|
||||
},
|
||||
t -> Timber.e(t, "Fetching picture of the day failed")
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@
|
|||
android:contentDescription="@string/mediaimage_failed"
|
||||
/>
|
||||
|
||||
<fr.free.nrw.commons.MediaWikiImageView
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/mediaDetailImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:actualImageScaleType="fitCenter"
|
||||
app:actualImageScaleType="fitXY"
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
android:layout_gravity="end|bottom"
|
||||
/>
|
||||
|
||||
<fr.free.nrw.commons.MediaWikiImageView
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/categoryImageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="240dp"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fresco="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="2dp"
|
||||
android:paddingBottom="0dp"
|
||||
>
|
||||
android:paddingBottom="0dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/contributionSequenceNumber"
|
||||
|
|
@ -18,11 +18,12 @@
|
|||
android:layout_gravity="end|bottom"
|
||||
/>
|
||||
|
||||
<fr.free.nrw.commons.MediaWikiImageView
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/contributionImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="240dp"
|
||||
app:actualImageScaleType="fitCenter"
|
||||
app:actualImageScaleType="fitXY"
|
||||
fresco:placeholderImage="@drawable/ic_image_black_24dp"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="MediaWikiImageView">
|
||||
<attr name="isThumbnail" format="boolean" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue