Skip to content

Conversation

@ashishkumar468
Copy link
Collaborator

Description (required)

Fixes #3045 Refactor Contributions

What changes did you make and why?

* Refactored ContributionsListFragment to use RecyclerView
* Added ContributionsPresenter
* Extracted out the cursor to presenter
* Probable fix for #3028
* Improved the logic for cache in ContributionViewHolder

Tests performed (required)

Tested {build variant, betaDebug} on Pixel-27

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ A review job has been created and sent to the PullRequest network.


Check the status or cancel PullRequest code review here.

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 Message
⚠️ Due to its size, this pull request will likely have a little longer turnaround time and will probably require multiple passes from our reviewers.

@codecov-io
Copy link

codecov-io commented Jun 30, 2019

Codecov Report

Merging #3046 into master will increase coverage by 0.25%.
The diff coverage is 14.47%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master   #3046      +/-   ##
=========================================
+ Coverage    4.41%   4.67%   +0.25%     
=========================================
  Files         259     264       +5     
  Lines       12309   12354      +45     
  Branches     1056    1051       -5     
=========================================
+ Hits          544     577      +33     
- Misses      11726   11734       +8     
- Partials       39      43       +4
Impacted Files Coverage Δ
.../nrw/commons/category/CategoryDetailsActivity.java 0% <ø> (ø) ⬆️
...va/fr/free/nrw/commons/explore/SearchActivity.java 0% <ø> (ø) ⬆️
...e/nrw/commons/category/CategoryImagesActivity.java 0% <ø> (ø) ⬆️
...r/free/nrw/commons/contributions/MainActivity.java 0% <ø> (ø) ⬆️
...rw/commons/explore/categories/ExploreActivity.java 0% <ø> (ø) ⬆️
.../free/nrw/commons/bookmarks/BookmarksActivity.java 0% <ø> (ø) ⬆️
...s/contributions/model/DisplayableContribution.java 0% <ø> (ø) ⬆️
...w/commons/contributions/ContributionsContract.java 0% <0%> (ø)
...fr/free/nrw/commons/media/MediaDetailFragment.java 0% <0%> (ø) ⬆️
...ommons/contributions/ContributionsListAdapter.java 0% <0%> (ø) ⬆️
... and 15 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0c3b002...cfb3eb3. Read the comment docs.

…completed && local uri exists, use that uri to show image
Copy link
Collaborator

@neslihanturan neslihanturan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ashishkumar468 , I see same images on fast scroll, instead of new ones. Then after a while correct images are displayed. Do you think this is related with this pull request?

@maskaravivek
Copy link
Contributor

@ashishkumar468 Does the PR fix #3028? If it does we can rebase the PR on 2.11-release branch.

@ashishkumar468
Copy link
Collaborator Author

Thanks for testing this out @neslihanturan . Should not be related to this PR, but this PR intends to fix those things. I will look into it and add a fix for the same
@maskaravivek are w sure we wanna add in the latest release branch ?

@maskaravivek
Copy link
Contributor

Yes, it is part of #3024 which is needed for 2.11. @misaochan can reconfirm.

@misaochan
Copy link
Member

Hmm. Yes, we do need a fix for #3028 , however this PR introduces many other changes as well (which is expected because it is also part of the refactor task). Would it be simple to isolate the part that fixes #3028 ? If yes, it would be easier to simply submit a different PR for that, because otherwise I would need to run the comprehensive tests all over again. Normally once I finish pre-release testing, I try to have minimal code changes so that we don't hit unexpected side effects.

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice work! I think that most of my comments are questions and minor suggestions.


Reviewed with ❤️ by PullRequest

import javax.inject.Inject;
import javax.inject.Named;

class ContributionsLocalDatSource {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be ContributionsLocalDataSource?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, my bad, I will do the correction

imageView.setBackground(null);
if ((contribution.getState() != Contribution.STATE_COMPLETED) && fileExists(
contribution.getLocalUri())) {
imageView.setImageURI(contribution.getLocalUri());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If getState() != Contribution.STATE_COMPLETED, does contribution.getLocalUri() have some temporary image?

Copy link
Collaborator Author

@ashishkumar468 ashishkumar468 Jul 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, contribution.localUri has the temporary uri for the image which is saved in the db while the upload is in progress

@Binds
public abstract ContributionsContract.UserActionListener bindsContibutionsPresenter(
ContributionsPresenter
presenter);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this should go on the previous line.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the formatting ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes—just formatting. :-)

}

@Override
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation of LoaderManager.LoaderCallbacks doesn't mention whether onLoadFinished is guaranteed to be called before onLoaderReset. I found a StackOverflow thread where one commenter says:

onLoaderReset(Loader) asks you to fulfill the same contract [as onLoadFinished], but without providing a replacement [cursor]

Thus, I would suggest that you turn off the progress bar and all of the tip, just to be sure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for letting me know, I will make the required changes


void registerDataSetObserver(DataSetObserver observer);

void unregisterDataSetObserver(DataSetObserver observer);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing these unused methods from the interface is a good idea.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do :-)


@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) {
view.showProgress(false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is view.showProgress(true)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is called from the parent fragment, that is the one which initialises the loader, the parent fragment of ContributionsListFragment and MediaDetailPagerFragment

rvContributionsList.setLayoutManager(gridLayoutManager);
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
fab_layout.setOrientation(LinearLayout.VERTICAL);
rvContributionsList.setLayoutManager(linearLayoutManager);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the things that is unclear to me is whether switching view managers like this will maintain the current scroll position. You wouldn't want to to pop up to the top just because the orientation changed. Likewise, because I believe these two maintain different scroll positions, you could get some strange effects by scrolling to different places in each orientation and then rotating the device to change back and forth.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, as a fix to that, we can store the id of the corresponding list item and use to id to request focus (bring to user's visible position) to that particular child

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a good plan.

public interface ViewHolder<T> {
void bindModel(Context context, T model);
void init(int position,
DisplayableContribution contribution);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused by this. ViewHolder is meant to be a generic holder object for a model (the generic T) and the Android context. It doesn't see appropriate to convert this to such a specific method. Perhaps this happened with some automated refactoring? I would strongly urge you to change it back and to introduce a new interface if necessary.

If you really want to go down this route, then you need to at least change ViewHolder to not have a generic parameter and rename the class to something more specific, like DisplayableContributionHolder. You may also want to move it to commons/contributions since that's where it seems to be used.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for figuring this out, yes I am planning to change it to void bindModel(int position, T model);, context is not required by the view holder, it can get it from its itemView, what do you think ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I think about it, ViewHolder<T> is a very generic interface—you should be able to call bindModel with any type. As soon as you add position to it, the interface is no longer generic—the model must have some idea of "position" that is an integer.

But maybe this doesn't really matter. In this change, you only call init(...) from onBindViewHolder, which takes a ContributionViewHolder. Thus you don't even need to implement ViewHolder.

Thus, I would suggest reverting the changes to ViewHolder<T> and making ContributionViewHolder not implement that interface.

What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have made ContributionViewHolder not implement the generic ViewHolder, later on when the model holds the position, it could be refactored to implement the ViewHolder

if ((contribution.getState() != Contribution.STATE_COMPLETED) && fileExists(
contribution.getLocalUri())) {
imageView.setImageURI(contribution.getLocalUri());
}else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space before else.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add :-)

}

public void onDataSetInvalidated() {
//Doing nothing as of now
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most other comments have a space after //. Also, you may want to describe briefly what should happen in the future.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, one of the comments landed on the wrong line.


Reviewed with ❤️ by PullRequest

*/
private String getKeyForLRUCache(Uri contentUri) {
String[] split = contentUri.toString().split("/");
return split[split.length-1];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using Uri.getLastPathSegment()—it seems to do what you want and is probably more efficient.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for letting me know, I will use the same :-)

Copy link
Contributor

@maskaravivek maskaravivek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

import fr.free.nrw.commons.BasePresenter;
import fr.free.nrw.commons.Media;

public class ContributionsContract {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add java docs

import android.database.Cursor;
import javax.inject.Inject;

public class ContributionsRepository {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

java docs

* @param localUri
* @return
*/
private boolean fileExists(Uri localUri) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to FileUtils

import timber.log.Timber;

public class ContributionViewHolder implements ViewHolder<DisplayableContribution> {
public class ContributionViewHolder extends RecyclerView.ViewHolder{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting

@ashishkumar468
Copy link
Collaborator Author

@neslihanturan, the image list bug (wrong image being showed), can it be taken as a separate bug fix ? I think that is anyways existing as of now (in master). That seems to be somewhat related to the underlying image library+ListView combination.

@neslihanturan
Copy link
Collaborator

Sure @ashishkumar468 , other parts seems good to me. And I didn't experienced any issues on my previous tests except displaying wrong image. So I can merge it after tests passed.

@ashishkumar468
Copy link
Collaborator Author

Thanks @neslihanturan :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor Contributions

5 participants