mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 04:43:54 +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
|
||||
@Nullable
|
||||
public Uri localUri;
|
||||
public String thumbUrl;
|
||||
public String imageUrl;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import androidx.room.OnConflictStrategy;
|
|||
import androidx.room.Query;
|
||||
import androidx.room.Transaction;
|
||||
|
||||
import androidx.room.Update;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
|
|
@ -52,4 +54,7 @@ public abstract class ContributionDao {
|
|||
|
||||
@Query("Delete FROM contribution WHERE state = :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;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.collection.LruCache;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
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.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
|
||||
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
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;
|
||||
import java.util.HashMap;
|
||||
import java.util.Random;
|
||||
|
||||
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.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 Contribution contribution;
|
||||
private Random random = new Random();
|
||||
|
||||
ContributionViewHolder(View parent, Callback callback) {
|
||||
super(parent);
|
||||
|
|
@ -58,15 +47,22 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
|||
this.callback=callback;
|
||||
}
|
||||
|
||||
public void init(int position, DisplayableContribution contribution) {
|
||||
ApplicationlessInjection.getInstance(itemView.getContext())
|
||||
.getCommonsApplicationComponent().inject(this);
|
||||
this.position=position;
|
||||
public void init(int position, 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());
|
||||
|
||||
seqNumView.setText(String.valueOf(contribution.getPosition() + 1));
|
||||
seqNumView.setText(String.valueOf(position + 1));
|
||||
seqNumView.setVisibility(View.VISIBLE);
|
||||
|
||||
switch (contribution.getState()) {
|
||||
|
|
@ -104,40 +100,18 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method fetches the thumbnail url from file name
|
||||
* If the thumbnail url is present in cache, then it is used otherwise API call is made to fetch the thumbnail
|
||||
* This can be removed once #2904 is in place and contribution contains all metadata beforehand
|
||||
* @param contribution
|
||||
* Returns the image source for the image view, first preference is given to thumbUrl if that is
|
||||
* null, moves to local uri and if both are null return null
|
||||
*
|
||||
* @param thumbUrl
|
||||
* @param localUri
|
||||
* @return
|
||||
*/
|
||||
private void fetchAndDisplayThumbnail(DisplayableContribution contribution) {
|
||||
String keyForLRUCache = contribution.getFilename();
|
||||
String cacheUrl = thumbnailCache.get(keyForLRUCache);
|
||||
if (!StringUtils.isBlank(cacheUrl)) {
|
||||
imageView.setImageURI(cacheUrl);
|
||||
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();
|
||||
@Nullable
|
||||
private String chooseImageSource(String thumbUrl, Uri localUri) {
|
||||
return !TextUtils.isEmpty(thumbUrl) ? thumbUrl :
|
||||
localUri != null ? localUri.toString() :
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,10 +26,15 @@ public class ContributionsContract {
|
|||
}
|
||||
|
||||
public interface UserActionListener extends BasePresenter<ContributionsContract.View> {
|
||||
|
||||
Contribution getContributionsWithTitle(String uri);
|
||||
|
||||
void deleteUpload(Contribution contribution);
|
||||
|
||||
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.FragmentTransaction;
|
||||
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
|
@ -216,6 +218,12 @@ public class ContributionsFragment
|
|||
public Contribution getContributionForPosition(int 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){
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
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.ViewGroup;
|
||||
|
||||
|
|
@ -10,7 +13,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
|
||||
|
||||
/**
|
||||
* Represents The View Adapter for the List of Contributions
|
||||
|
|
@ -22,7 +24,7 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
|||
|
||||
public ContributionsListAdapter(Callback callback) {
|
||||
this.callback = callback;
|
||||
contributions=new ArrayList<>();
|
||||
contributions = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -41,9 +43,12 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
|||
@Override
|
||||
public void onBindViewHolder(@NonNull ContributionViewHolder holder, int position) {
|
||||
final Contribution contribution = contributions.get(position);
|
||||
DisplayableContribution displayableContribution = new DisplayableContribution(contribution,
|
||||
position);
|
||||
holder.init(position, displayableContribution);
|
||||
if (TextUtils.isEmpty(contribution.getThumbUrl())
|
||||
&& contribution.getState() == Contribution.STATE_COMPLETED) {
|
||||
callback.fetchMediaUriFor(contribution);
|
||||
}
|
||||
|
||||
holder.init(position, contribution);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -51,12 +56,14 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
|||
return contributions.size();
|
||||
}
|
||||
|
||||
public void setContributions(List<Contribution> contributionList) {
|
||||
if(null!=contributionList) {
|
||||
this.contributions.clear();
|
||||
this.contributions.addAll(contributionList);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
public void setContributions(@NonNull List<Contribution> contributionList) {
|
||||
contributions = contributionList;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return contributions.get(position)._id;
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
|
|
@ -68,5 +75,7 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
|
|||
void openMediaDetail(int contribution);
|
||||
|
||||
Contribution getContributionForPosition(int position);
|
||||
|
||||
void fetchMediaUriFor(Contribution contribution);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
|||
|
||||
private void initAdapter() {
|
||||
adapter = new ContributionsListAdapter(callback);
|
||||
adapter.setHasStableIds(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -74,4 +74,8 @@ class ContributionsLocalDataSource {
|
|||
public void set(String key, long 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.Observer;
|
||||
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -62,6 +63,10 @@ public class ContributionsPresenter implements UserActionListener {
|
|||
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
|
||||
@Inject
|
||||
MediaDataExtractor mediaDataExtractor;
|
||||
|
||||
private LifecycleOwner lifeCycleOwner;
|
||||
|
||||
@Inject
|
||||
|
|
@ -180,4 +185,24 @@ public class ContributionsPresenter implements UserActionListener {
|
|||
}
|
||||
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) {
|
||||
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(ContributionViewHolder viewHolder);
|
||||
|
||||
Gson gson();
|
||||
|
||||
@Component.Builder
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue