Skip to content

Commit 20af16f

Browse files
* 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
1 parent ed5f8ef commit 20af16f

11 files changed

+91
-115
lines changed

app/src/main/java/fr/free/nrw/commons/Media.java

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public Media[] newArray(int i) {
4545
};
4646

4747
// Primary metadata fields
48+
@Nullable
4849
public Uri localUri;
4950
public String thumbUrl;
5051
public String imageUrl;

app/src/main/java/fr/free/nrw/commons/contributions/ContributionDao.java

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import androidx.room.Query;
99
import androidx.room.Transaction;
1010

11+
import androidx.room.Update;
12+
import io.reactivex.disposables.Disposable;
1113
import java.util.List;
1214

1315
import io.reactivex.Completable;
@@ -52,4 +54,7 @@ public void deleteAllAndSaveTransaction(List<Contribution> contributions){
5254

5355
@Query("Delete FROM contribution WHERE state = :state")
5456
public abstract void deleteAll(int state);
57+
58+
@Update
59+
public abstract Single<Integer> update(Contribution contribution);
5560
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionViewHolder.java

+22-66
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,26 @@
11
package fr.free.nrw.commons.contributions;
22

3+
import android.net.Uri;
4+
import android.text.TextUtils;
5+
import android.util.Log;
36
import android.view.View;
47
import android.widget.LinearLayout;
58
import android.widget.ProgressBar;
69
import android.widget.TextView;
710

8-
import androidx.collection.LruCache;
911
import androidx.recyclerview.widget.RecyclerView;
1012

1113
import com.facebook.drawee.view.SimpleDraweeView;
1214

13-
import org.apache.commons.lang3.StringUtils;
15+
import com.facebook.imagepipeline.request.ImageRequest;
16+
import com.facebook.imagepipeline.request.ImageRequestBuilder;
1417

15-
import javax.inject.Inject;
16-
import javax.inject.Named;
1718

1819
import butterknife.BindView;
1920
import butterknife.ButterKnife;
2021
import butterknife.OnClick;
21-
import fr.free.nrw.commons.MediaDataExtractor;
2222
import fr.free.nrw.commons.R;
2323
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
24-
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
25-
import fr.free.nrw.commons.di.ApplicationlessInjection;
26-
import fr.free.nrw.commons.upload.FileUtils;
27-
import io.reactivex.android.schedulers.AndroidSchedulers;
28-
import io.reactivex.disposables.CompositeDisposable;
29-
import io.reactivex.disposables.Disposable;
30-
import io.reactivex.schedulers.Schedulers;
31-
import timber.log.Timber;
3224

3325
public class ContributionViewHolder extends RecyclerView.ViewHolder {
3426

@@ -41,32 +33,33 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
4133
@BindView(R.id.contributionProgress) ProgressBar progressView;
4234
@BindView(R.id.failed_image_options) LinearLayout failedImageOptions;
4335

44-
@Inject
45-
MediaDataExtractor mediaDataExtractor;
46-
47-
@Inject
48-
@Named("thumbnail-cache")
49-
LruCache<String, String> thumbnailCache;
50-
51-
private DisplayableContribution contribution;
52-
private CompositeDisposable compositeDisposable = new CompositeDisposable();
53-
private int position;
36+
int position;
37+
private Contribution contribution;
5438

5539
ContributionViewHolder(View parent, Callback callback) {
5640
super(parent);
5741
ButterKnife.bind(this, parent);
5842
this.callback=callback;
5943
}
6044

61-
public void init(int position, DisplayableContribution contribution) {
62-
ApplicationlessInjection.getInstance(itemView.getContext())
63-
.getCommonsApplicationComponent().inject(this);
45+
public void init(int position, Contribution contribution) {
46+
this.contribution=contribution;
6447
this.position=position;
65-
this.contribution = contribution;
66-
fetchAndDisplayThumbnail(contribution);
48+
String imageSource = contribution.thumbUrl;
49+
if (TextUtils.isEmpty(imageSource)) {
50+
imageSource =
51+
contribution.getLocalUri() != null ? contribution.getLocalUri().toString()
52+
: null;
53+
}
54+
if (!TextUtils.isEmpty(imageSource)) {
55+
final ImageRequest imageRequest =
56+
ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageSource)).setProgressiveRenderingEnabled(true).setProgressiveRenderingEnabled(true)
57+
.build();
58+
imageView.setImageRequest(imageRequest);
59+
}
6760
titleView.setText(contribution.getDisplayTitle());
6861

69-
seqNumView.setText(String.valueOf(contribution.getPosition() + 1));
62+
seqNumView.setText(String.valueOf(position + 1));
7063
seqNumView.setVisibility(View.VISIBLE);
7164

7265
switch (contribution.getState()) {
@@ -103,43 +96,6 @@ public void init(int position, DisplayableContribution contribution) {
10396
}
10497
}
10598

106-
/**
107-
* This method fetches the thumbnail url from file name
108-
* If the thumbnail url is present in cache, then it is used otherwise API call is made to fetch the thumbnail
109-
* This can be removed once #2904 is in place and contribution contains all metadata beforehand
110-
* @param contribution
111-
*/
112-
private void fetchAndDisplayThumbnail(DisplayableContribution contribution) {
113-
String keyForLRUCache = contribution.getFilename();
114-
String cacheUrl = thumbnailCache.get(keyForLRUCache);
115-
if (!StringUtils.isBlank(cacheUrl)) {
116-
imageView.setImageURI(cacheUrl);
117-
return;
118-
}
119-
120-
imageView.setBackground(null);
121-
if ((contribution.getState() != Contribution.STATE_COMPLETED) && FileUtils.fileExists(
122-
contribution.getLocalUri())) {
123-
imageView.setImageURI(contribution.getLocalUri());
124-
} else {
125-
Timber.d("Fetching thumbnail for %s", contribution.getFilename());
126-
Disposable disposable = mediaDataExtractor
127-
.getMediaFromFileName(contribution.getFilename())
128-
.subscribeOn(Schedulers.io())
129-
.observeOn(AndroidSchedulers.mainThread())
130-
.subscribe(media -> {
131-
thumbnailCache.put(keyForLRUCache, media.getThumbUrl());
132-
imageView.setImageURI(media.getThumbUrl());
133-
});
134-
compositeDisposable.add(disposable);
135-
}
136-
137-
}
138-
139-
public void clear() {
140-
compositeDisposable.clear();
141-
}
142-
14399
/**
144100
* Retry upload when it is failed
145101
*/

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java

+5
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ public interface View {
2626
}
2727

2828
public interface UserActionListener extends BasePresenter<ContributionsContract.View> {
29+
2930
Contribution getContributionsWithTitle(String uri);
3031

3132
void deleteUpload(Contribution contribution);
3233

3334
Media getItemAtPosition(int i);
35+
36+
void updateContribution(Contribution contribution);
37+
38+
void fetchMediaDetails(Contribution contribution);
3439
}
3540
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
2121
import androidx.fragment.app.FragmentTransaction;
2222

23+
import fr.free.nrw.commons.MediaDataExtractor;
24+
import io.reactivex.disposables.Disposable;
2325
import java.util.List;
2426

2527
import javax.inject.Inject;
@@ -77,6 +79,8 @@ public class ContributionsFragment
7779
@Inject OkHttpJsonApiClient okHttpJsonApiClient;
7880
@Inject CampaignsPresenter presenter;
7981
@Inject LocationServiceManager locationManager;
82+
@Inject
83+
MediaDataExtractor mediaDataExtractor;
8084

8185
private UploadService uploadService;
8286
private boolean isUploadServiceConnected;
@@ -216,6 +220,12 @@ public void openMediaDetail(int position) {
216220
public Contribution getContributionForPosition(int position) {
217221
return (Contribution) contributionsPresenter.getItemAtPosition(position);
218222
}
223+
224+
@Override
225+
public void fetchMediaUriFor(Contribution contribution) {
226+
Timber.d("Fetching thumbnail for %s", contribution.filename);
227+
contributionsPresenter.fetchMediaDetails(contribution);
228+
}
219229
});
220230

221231
if(null==mediaDetailPagerFragment){

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package fr.free.nrw.commons.contributions;
22

3+
import android.os.Handler;
4+
import android.os.Looper;
5+
import android.text.TextUtils;
36
import android.view.LayoutInflater;
47
import android.view.ViewGroup;
58

@@ -10,7 +13,6 @@
1013
import java.util.List;
1114

1215
import fr.free.nrw.commons.R;
13-
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
1416

1517
/**
1618
* Represents The View Adapter for the List of Contributions
@@ -22,7 +24,7 @@ public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionV
2224

2325
public ContributionsListAdapter(Callback callback) {
2426
this.callback = callback;
25-
contributions=new ArrayList<>();
27+
contributions = new ArrayList<>();
2628
}
2729

2830
/**
@@ -41,22 +43,22 @@ public ContributionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int
4143
@Override
4244
public void onBindViewHolder(@NonNull ContributionViewHolder holder, int position) {
4345
final Contribution contribution = contributions.get(position);
44-
DisplayableContribution displayableContribution = new DisplayableContribution(contribution,
45-
position);
46-
holder.init(position, displayableContribution);
46+
if (TextUtils.isEmpty(contribution.getThumbUrl())
47+
&& contribution.getState() == Contribution.STATE_COMPLETED) {
48+
callback.fetchMediaUriFor(contribution);
49+
}
50+
51+
holder.init(position, contribution);
4752
}
4853

4954
@Override
5055
public int getItemCount() {
5156
return contributions.size();
5257
}
5358

54-
public void setContributions(List<Contribution> contributionList) {
55-
if(null!=contributionList) {
56-
this.contributions.clear();
57-
this.contributions.addAll(contributionList);
58-
notifyDataSetChanged();
59-
}
59+
public void setContributions(@NonNull List<Contribution> contributionList) {
60+
contributions = contributionList;
61+
notifyDataSetChanged();
6062
}
6163

6264
public interface Callback {
@@ -68,5 +70,7 @@ public interface Callback {
6870
void openMediaDetail(int contribution);
6971

7072
Contribution getContributionForPosition(int position);
73+
74+
void fetchMediaUriFor(Contribution contribution);
7175
}
7276
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsLocalDataSource.java

+4
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,8 @@ public Completable saveContributions(List<Contribution> contributions) {
7474
public void set(String key, long value) {
7575
defaultKVStore.putLong(key,value);
7676
}
77+
78+
public Single<Integer> updateContribution(Contribution contribution) {
79+
return contributionDao.update(contribution);
80+
}
7781
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java

+25
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import androidx.lifecycle.LiveData;
1313
import androidx.lifecycle.Observer;
1414

15+
import fr.free.nrw.commons.MediaDataExtractor;
1516
import java.util.ArrayList;
1617
import java.util.Collections;
1718
import java.util.List;
@@ -62,6 +63,10 @@ public class ContributionsPresenter implements UserActionListener {
6263

6364
@Inject
6465
SessionManager sessionManager;
66+
67+
@Inject
68+
MediaDataExtractor mediaDataExtractor;
69+
6570
private LifecycleOwner lifeCycleOwner;
6671

6772
@Inject
@@ -180,4 +185,24 @@ public Media getItemAtPosition(int i) {
180185
}
181186
return contributionList.get(i);
182187
}
188+
189+
@Override
190+
public void updateContribution(Contribution contribution) {
191+
compositeDisposable.add(repository
192+
.updateContribution(contribution)
193+
.subscribeOn(ioThreadScheduler)
194+
.subscribe());
195+
}
196+
197+
@Override
198+
public void fetchMediaDetails(Contribution contribution) {
199+
compositeDisposable.add(mediaDataExtractor
200+
.getMediaFromFileName(contribution.filename)
201+
.subscribeOn(Schedulers.io())
202+
.observeOn(AndroidSchedulers.mainThread())
203+
.subscribe(media -> {
204+
contribution.thumbUrl=media.thumbUrl;
205+
updateContribution(contribution);
206+
}));
207+
}
183208
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsRepository.java

+4
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,8 @@ public void set(String key, long value) {
6161
public long getLong(String key) {
6262
return localDataSource.getLong(key);
6363
}
64+
65+
public Single<Integer> updateContribution(Contribution contribution) {
66+
return localDataSource.updateContribution(contribution);
67+
}
6468
}

app/src/main/java/fr/free/nrw/commons/contributions/model/DisplayableContribution.java

-36
This file was deleted.

app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java

-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application
5353

5454
void inject(PicOfDayAppWidget picOfDayAppWidget);
5555

56-
void inject(ContributionViewHolder viewHolder);
57-
5856
Gson gson();
5957

6058
@Component.Builder

0 commit comments

Comments
 (0)