mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 12:53:55 +01:00
* Fixes #3359 * Cache thumb url & imageUrl in local db * Use Fresco's ImageRequest to show images in ContributionViewHolder[this was the issue, we should have always used this to show the image] * Deleted DisplayableContribution (not needed anymore) * Exposed abstract function in ContributionDao to updateContribution * * Make position private in ContributionViewHolder * Remove MediaDataExtractor from ContributionsFragment * * Show placeholder image for Contributions while the image loads * setHasStableId's ContributionsAdapter * make Random variable private in ContributionViewHolder * replace local variable-if-with ternary operator in ContributionViewHolder * Fix indentation/formatting of ternary operator in ContributionViewHolder * I might revert this commit[I have reasons] * Create in-memory drawables in CVH's onBind, caches are bad, add mental overhead * Revert "I might revert this commit[I have reasons]" This reverts commit627ac91517. * minor formatting changes, reverted627ac91517* uh-oh missed semicolon, java * minor formatting changes
This commit is contained in:
parent
021105ac4d
commit
efdb00b5ee
12 changed files with 108 additions and 110 deletions
|
|
@ -45,6 +45,7 @@ public class Media implements Parcelable {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Primary metadata fields
|
// Primary metadata fields
|
||||||
|
@Nullable
|
||||||
public Uri localUri;
|
public Uri localUri;
|
||||||
public String thumbUrl;
|
public String thumbUrl;
|
||||||
public String imageUrl;
|
public String imageUrl;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import androidx.room.OnConflictStrategy;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
import androidx.room.Transaction;
|
import androidx.room.Transaction;
|
||||||
|
|
||||||
|
import androidx.room.Update;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
|
@ -52,4 +54,7 @@ public abstract class ContributionDao {
|
||||||
|
|
||||||
@Query("Delete FROM contribution WHERE state = :state")
|
@Query("Delete FROM contribution WHERE state = :state")
|
||||||
public abstract void deleteAll(int state);
|
public abstract void deleteAll(int state);
|
||||||
|
|
||||||
|
@Update
|
||||||
|
public abstract Single<Integer> update(Contribution contribution);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,30 @@
|
||||||
package fr.free.nrw.commons.contributions;
|
package fr.free.nrw.commons.contributions;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.collection.LruCache;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.facebook.drawee.view.SimpleDraweeView;
|
import com.facebook.drawee.view.SimpleDraweeView;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import com.facebook.imagepipeline.request.ImageRequest;
|
||||||
|
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import butterknife.OnClick;
|
import butterknife.OnClick;
|
||||||
import fr.free.nrw.commons.MediaDataExtractor;
|
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
|
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
|
||||||
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
|
import java.util.HashMap;
|
||||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
import java.util.Random;
|
||||||
import fr.free.nrw.commons.upload.FileUtils;
|
|
||||||
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 ContributionViewHolder extends RecyclerView.ViewHolder {
|
public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
|
@ -41,16 +37,9 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
||||||
@BindView(R.id.contributionProgress) ProgressBar progressView;
|
@BindView(R.id.contributionProgress) ProgressBar progressView;
|
||||||
@BindView(R.id.failed_image_options) LinearLayout failedImageOptions;
|
@BindView(R.id.failed_image_options) LinearLayout failedImageOptions;
|
||||||
|
|
||||||
@Inject
|
|
||||||
MediaDataExtractor mediaDataExtractor;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
@Named("thumbnail-cache")
|
|
||||||
LruCache<String, String> thumbnailCache;
|
|
||||||
|
|
||||||
private DisplayableContribution contribution;
|
|
||||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
|
||||||
private int position;
|
private int position;
|
||||||
|
private Contribution contribution;
|
||||||
|
private Random random = new Random();
|
||||||
|
|
||||||
ContributionViewHolder(View parent, Callback callback) {
|
ContributionViewHolder(View parent, Callback callback) {
|
||||||
super(parent);
|
super(parent);
|
||||||
|
|
@ -58,15 +47,22 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
||||||
this.callback=callback;
|
this.callback=callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(int position, DisplayableContribution contribution) {
|
public void init(int position, Contribution contribution) {
|
||||||
ApplicationlessInjection.getInstance(itemView.getContext())
|
|
||||||
.getCommonsApplicationComponent().inject(this);
|
|
||||||
this.position=position;
|
|
||||||
this.contribution = contribution;
|
this.contribution = contribution;
|
||||||
fetchAndDisplayThumbnail(contribution);
|
this.position = position;
|
||||||
|
imageView.getHierarchy().setPlaceholderImage(new ColorDrawable(
|
||||||
|
Color.argb(100, random.nextInt(256), random.nextInt(256), random.nextInt(256))));
|
||||||
|
String imageSource = chooseImageSource(contribution.thumbUrl, contribution.getLocalUri());
|
||||||
|
if (!TextUtils.isEmpty(imageSource)) {
|
||||||
|
final ImageRequest imageRequest =
|
||||||
|
ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageSource))
|
||||||
|
.setProgressiveRenderingEnabled(true)
|
||||||
|
.build();
|
||||||
|
imageView.setImageRequest(imageRequest);
|
||||||
|
}
|
||||||
titleView.setText(contribution.getDisplayTitle());
|
titleView.setText(contribution.getDisplayTitle());
|
||||||
|
|
||||||
seqNumView.setText(String.valueOf(contribution.getPosition() + 1));
|
seqNumView.setText(String.valueOf(position + 1));
|
||||||
seqNumView.setVisibility(View.VISIBLE);
|
seqNumView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
switch (contribution.getState()) {
|
switch (contribution.getState()) {
|
||||||
|
|
@ -104,40 +100,18 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method fetches the thumbnail url from file name
|
* Returns the image source for the image view, first preference is given to thumbUrl if that is
|
||||||
* If the thumbnail url is present in cache, then it is used otherwise API call is made to fetch the thumbnail
|
* null, moves to local uri and if both are null return null
|
||||||
* This can be removed once #2904 is in place and contribution contains all metadata beforehand
|
*
|
||||||
* @param contribution
|
* @param thumbUrl
|
||||||
|
* @param localUri
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
private void fetchAndDisplayThumbnail(DisplayableContribution contribution) {
|
@Nullable
|
||||||
String keyForLRUCache = contribution.getFilename();
|
private String chooseImageSource(String thumbUrl, Uri localUri) {
|
||||||
String cacheUrl = thumbnailCache.get(keyForLRUCache);
|
return !TextUtils.isEmpty(thumbUrl) ? thumbUrl :
|
||||||
if (!StringUtils.isBlank(cacheUrl)) {
|
localUri != null ? localUri.toString() :
|
||||||
imageView.setImageURI(cacheUrl);
|
null;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
imageView.setBackground(null);
|
|
||||||
if ((contribution.getState() != Contribution.STATE_COMPLETED) && FileUtils.fileExists(
|
|
||||||
contribution.getLocalUri())) {
|
|
||||||
imageView.setImageURI(contribution.getLocalUri());
|
|
||||||
} else {
|
|
||||||
Timber.d("Fetching thumbnail for %s", contribution.getFilename());
|
|
||||||
Disposable disposable = mediaDataExtractor
|
|
||||||
.getMediaFromFileName(contribution.getFilename())
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(media -> {
|
|
||||||
thumbnailCache.put(keyForLRUCache, media.getThumbUrl());
|
|
||||||
imageView.setImageURI(media.getThumbUrl());
|
|
||||||
});
|
|
||||||
compositeDisposable.add(disposable);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
compositeDisposable.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,15 @@ public class ContributionsContract {
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface UserActionListener extends BasePresenter<ContributionsContract.View> {
|
public interface UserActionListener extends BasePresenter<ContributionsContract.View> {
|
||||||
|
|
||||||
Contribution getContributionsWithTitle(String uri);
|
Contribution getContributionsWithTitle(String uri);
|
||||||
|
|
||||||
void deleteUpload(Contribution contribution);
|
void deleteUpload(Contribution contribution);
|
||||||
|
|
||||||
Media getItemAtPosition(int i);
|
Media getItemAtPosition(int i);
|
||||||
|
|
||||||
|
void updateContribution(Contribution contribution);
|
||||||
|
|
||||||
|
void fetchMediaDetails(Contribution contribution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
|
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.MediaDataExtractor;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
@ -216,6 +218,12 @@ public class ContributionsFragment
|
||||||
public Contribution getContributionForPosition(int position) {
|
public Contribution getContributionForPosition(int position) {
|
||||||
return (Contribution) contributionsPresenter.getItemAtPosition(position);
|
return (Contribution) contributionsPresenter.getItemAtPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fetchMediaUriFor(Contribution contribution) {
|
||||||
|
Timber.d("Fetching thumbnail for %s", contribution.filename);
|
||||||
|
contributionsPresenter.fetchMediaDetails(contribution);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(null==mediaDetailPagerFragment){
|
if(null==mediaDetailPagerFragment){
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
package fr.free.nrw.commons.contributions;
|
package fr.free.nrw.commons.contributions;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
|
@ -10,7 +13,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents The View Adapter for the List of Contributions
|
* Represents The View Adapter for the List of Contributions
|
||||||
|
|
@ -22,7 +24,7 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
||||||
|
|
||||||
public ContributionsListAdapter(Callback callback) {
|
public ContributionsListAdapter(Callback callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
contributions=new ArrayList<>();
|
contributions = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -41,9 +43,12 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ContributionViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ContributionViewHolder holder, int position) {
|
||||||
final Contribution contribution = contributions.get(position);
|
final Contribution contribution = contributions.get(position);
|
||||||
DisplayableContribution displayableContribution = new DisplayableContribution(contribution,
|
if (TextUtils.isEmpty(contribution.getThumbUrl())
|
||||||
position);
|
&& contribution.getState() == Contribution.STATE_COMPLETED) {
|
||||||
holder.init(position, displayableContribution);
|
callback.fetchMediaUriFor(contribution);
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.init(position, contribution);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -51,12 +56,14 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
||||||
return contributions.size();
|
return contributions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContributions(List<Contribution> contributionList) {
|
public void setContributions(@NonNull List<Contribution> contributionList) {
|
||||||
if(null!=contributionList) {
|
contributions = contributionList;
|
||||||
this.contributions.clear();
|
notifyDataSetChanged();
|
||||||
this.contributions.addAll(contributionList);
|
}
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return contributions.get(position)._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
|
|
@ -68,5 +75,7 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
||||||
void openMediaDetail(int contribution);
|
void openMediaDetail(int contribution);
|
||||||
|
|
||||||
Contribution getContributionForPosition(int position);
|
Contribution getContributionForPosition(int position);
|
||||||
|
|
||||||
|
void fetchMediaUriFor(Contribution contribution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
||||||
|
|
||||||
private void initAdapter() {
|
private void initAdapter() {
|
||||||
adapter = new ContributionsListAdapter(callback);
|
adapter = new ContributionsListAdapter(callback);
|
||||||
|
adapter.setHasStableIds(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -74,4 +74,8 @@ class ContributionsLocalDataSource {
|
||||||
public void set(String key, long value) {
|
public void set(String key, long value) {
|
||||||
defaultKVStore.putLong(key,value);
|
defaultKVStore.putLong(key,value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Single<Integer> updateContribution(Contribution contribution) {
|
||||||
|
return contributionDao.update(contribution);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.Observer;
|
import androidx.lifecycle.Observer;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.MediaDataExtractor;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -62,6 +63,10 @@ public class ContributionsPresenter implements UserActionListener {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SessionManager sessionManager;
|
SessionManager sessionManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MediaDataExtractor mediaDataExtractor;
|
||||||
|
|
||||||
private LifecycleOwner lifeCycleOwner;
|
private LifecycleOwner lifeCycleOwner;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|
@ -180,4 +185,24 @@ public class ContributionsPresenter implements UserActionListener {
|
||||||
}
|
}
|
||||||
return contributionList.get(i);
|
return contributionList.get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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.filename)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(media -> {
|
||||||
|
contribution.thumbUrl=media.thumbUrl;
|
||||||
|
updateContribution(contribution);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,4 +61,8 @@ public class ContributionsRepository {
|
||||||
public long getLong(String key) {
|
public long getLong(String key) {
|
||||||
return localDataSource.getLong(key);
|
return localDataSource.getLong(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Single<Integer> updateContribution(Contribution contribution) {
|
||||||
|
return localDataSource.updateContribution(contribution);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package fr.free.nrw.commons.contributions.model;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
|
||||||
|
|
||||||
public class DisplayableContribution extends Contribution {
|
|
||||||
private int position;
|
|
||||||
public DisplayableContribution(Contribution contribution,
|
|
||||||
int position) {
|
|
||||||
super(contribution.getContentUri(),
|
|
||||||
contribution.getFilename(),
|
|
||||||
contribution.getLocalUri(),
|
|
||||||
contribution.getImageUrl(),
|
|
||||||
contribution.getDateCreated(),
|
|
||||||
contribution.getState(),
|
|
||||||
contribution.getDataLength(),
|
|
||||||
contribution.getDateUploaded(),
|
|
||||||
contribution.getTransferred(),
|
|
||||||
contribution.getSource(),
|
|
||||||
contribution.getDescription(),
|
|
||||||
contribution.getCreator(),
|
|
||||||
contribution.getMultiple(),
|
|
||||||
contribution.getWidth(),
|
|
||||||
contribution.getHeight(),
|
|
||||||
contribution.getLicense());
|
|
||||||
this._id=contribution._id;
|
|
||||||
this.position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPosition() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPosition(int position) {
|
|
||||||
this.position = position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -53,8 +53,6 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application
|
||||||
|
|
||||||
void inject(PicOfDayAppWidget picOfDayAppWidget);
|
void inject(PicOfDayAppWidget picOfDayAppWidget);
|
||||||
|
|
||||||
void inject(ContributionViewHolder viewHolder);
|
|
||||||
|
|
||||||
Gson gson();
|
Gson gson();
|
||||||
|
|
||||||
@Component.Builder
|
@Component.Builder
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue