diff --git a/app/src/main/java/fr/free/nrw/commons/Media.java b/app/src/main/java/fr/free/nrw/commons/Media.java index 5bcc7bcdd..7093d2ce4 100644 --- a/app/src/main/java/fr/free/nrw/commons/Media.java +++ b/app/src/main/java/fr/free/nrw/commons/Media.java @@ -45,6 +45,7 @@ public class Media implements Parcelable { }; // Primary metadata fields + @Nullable public Uri localUri; public String thumbUrl; public String imageUrl; diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java index b4d0a8659..261784b52 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java @@ -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 update(Contribution contribution); } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionViewHolder.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionViewHolder.java index 22e342053..eae00b916 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionViewHolder.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionViewHolder.java @@ -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 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; } /** diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java index 90120d379..8b0049004 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java @@ -26,10 +26,15 @@ public class ContributionsContract { } public interface UserActionListener extends BasePresenter { + Contribution getContributionsWithTitle(String uri); void deleteUpload(Contribution contribution); Media getItemAtPosition(int i); + + void updateContribution(Contribution contribution); + + void fetchMediaDetails(Contribution contribution); } } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java index 25e20cc7a..e441ff51c 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java @@ -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){ diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java index 234222c92..8b8d2fff1 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java @@ -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(); + contributions = new ArrayList<>(); } /** @@ -41,9 +43,12 @@ public class ContributionsListAdapter extends RecyclerView.Adapter contributionList) { - if(null!=contributionList) { - this.contributions.clear(); - this.contributions.addAll(contributionList); - notifyDataSetChanged(); - } + public void setContributions(@NonNull List 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 updateContribution(Contribution contribution) { + return contributionDao.update(contribution); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java index 2845eec15..052ba110e 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java @@ -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); + })); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsRepository.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsRepository.java index 10e0878ec..500babaf5 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsRepository.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsRepository.java @@ -61,4 +61,8 @@ public class ContributionsRepository { public long getLong(String key) { return localDataSource.getLong(key); } + + public Single updateContribution(Contribution contribution) { + return localDataSource.updateContribution(contribution); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/model/DisplayableContribution.java b/app/src/main/java/fr/free/nrw/commons/contributions/model/DisplayableContribution.java deleted file mode 100644 index 064cdabdf..000000000 --- a/app/src/main/java/fr/free/nrw/commons/contributions/model/DisplayableContribution.java +++ /dev/null @@ -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; - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java index d8998b2c0..6efd3eb05 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java @@ -53,8 +53,6 @@ public interface CommonsApplicationComponent extends AndroidInjector