Fixes #3389 - Show User profiles (#4678)

* Fixes #3389 - Show  User profiles

* Don't show dummy achievements data - show data only when loaded
This commit is contained in:
Ashish 2021-10-26 02:10:08 +05:30 committed by GitHub
parent 7ce80aa804
commit 88b21a678e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 358 additions and 48 deletions

View file

@ -21,6 +21,8 @@ class ContributionBoundaryCallback @Inject constructor(
@param:Named(CommonsApplicationModule.IO_THREAD) private val ioThreadScheduler: Scheduler
) : BoundaryCallback<Contribution>() {
private val compositeDisposable: CompositeDisposable = CompositeDisposable()
lateinit var userName: String
/**
* It is triggered when the list has no items User's Contributions are then fetched from the
@ -55,7 +57,7 @@ class ContributionBoundaryCallback @Inject constructor(
fun fetchContributions() {
if (sessionManager.userName != null) {
compositeDisposable.add(
mediaClient.getMediaListForUser(sessionManager.userName!!)
mediaClient.getMediaListForUser(userName!!)
.map { mediaList ->
mediaList.map {
Contribution(media = it, state = Contribution.STATE_COMPLETED)
@ -88,4 +90,11 @@ class ContributionBoundaryCallback @Inject constructor(
}
)
}
/**
* Clean up
*/
fun dispose() {
compositeDisposable.dispose()
}
}

View file

@ -5,7 +5,6 @@ import static android.view.View.VISIBLE;
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
@ -21,6 +20,7 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -35,17 +35,20 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.customselector.ui.selector.CustomSelectorActivity;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.media.MediaClient;
import fr.free.nrw.commons.utils.SystemThemeUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import java.util.Locale;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.commons.lang3.StringUtils;
import org.wikipedia.dataclient.WikiSite;
import timber.log.Timber;
import fr.free.nrw.commons.profile.ProfileActivity;
/**
* Created by root on 01.06.2018.
@ -56,7 +59,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
WikipediaInstructionsDialogFragment.Callback {
private static final String RV_STATE = "rv_scroll_state";
@BindView(R.id.contributionsList)
RecyclerView rvContributionsList;
@BindView(R.id.loadingContributionsProgressBar)
@ -76,6 +79,8 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
@Inject
SystemThemeUtils systemThemeUtils;
@BindView(R.id.tv_contributions_of_user)
AppCompatTextView tvContributionsOfUser;
@Inject
ContributionController controller;
@ -89,6 +94,9 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
@Inject
ContributionsListPresenter contributionsListPresenter;
@Inject
SessionManager sessionManager;
private Animation fab_close;
private Animation fab_open;
private Animation rotate_forward;
@ -105,8 +113,23 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
private final int SPAN_COUNT_PORTRAIT = 1;
private int contributionsSize;
String userName;
@Override
public void onCreate(@Nullable @org.jetbrains.annotations.Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Now that we are allowing this fragment to be started for
// any userName- we expect it to be passed as an argument
if (getArguments() != null) {
userName = getArguments().getString(ProfileActivity.KEY_USERNAME);
}
if (StringUtils.isEmpty(userName)) {
userName = sessionManager.getUserName();
}
}
@Override
public View onCreateView(
final LayoutInflater inflater, @Nullable final ViewGroup container,
@ -114,6 +137,16 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
final View view = inflater.inflate(R.layout.fragment_contributions_list, container, false);
ButterKnife.bind(this, view);
contributionsListPresenter.onAttachView(this);
if (Objects.equals(sessionManager.getUserName(), userName)) {
tvContributionsOfUser.setVisibility(GONE);
fab_layout.setVisibility(VISIBLE);
} else {
tvContributionsOfUser.setVisibility(VISIBLE);
tvContributionsOfUser.setText(getString(R.string.contributions_of_user, userName));
fab_layout.setVisibility(GONE);
}
initAdapter();
return view;
}
@ -155,8 +188,9 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
contributionsListPresenter.setup();
contributionsListPresenter.contributionList.observe(this.getViewLifecycleOwner(), list -> {
contributionsListPresenter.setup(userName,
Objects.equals(sessionManager.getUserName(), userName));
contributionsListPresenter.contributionList.observe(getViewLifecycleOwner(), list -> {
contributionsSize = list.size();
adapter.submitList(list);
if (callback != null) {

View file

@ -1,6 +1,9 @@
package fr.free.nrw.commons.contributions;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.paging.DataSource;
import androidx.paging.DataSource.Factory;
import androidx.paging.LivePagedListBuilder;
import androidx.paging.PagedList;
import fr.free.nrw.commons.contributions.ContributionsListContract.UserActionListener;
@ -20,17 +23,20 @@ public class ContributionsListPresenter implements UserActionListener {
private final Scheduler ioThreadScheduler;
private final CompositeDisposable compositeDisposable;
private final ContributionsRemoteDataSource contributionsRemoteDataSource;
LiveData<PagedList<Contribution>> contributionList;
@Inject
ContributionsListPresenter(
final ContributionBoundaryCallback contributionBoundaryCallback,
final ContributionsRemoteDataSource contributionsRemoteDataSource,
final ContributionsRepository repository,
@Named(CommonsApplicationModule.IO_THREAD) final Scheduler ioThreadScheduler) {
this.contributionBoundaryCallback = contributionBoundaryCallback;
this.repository = repository;
this.ioThreadScheduler = ioThreadScheduler;
this.contributionsRemoteDataSource=contributionsRemoteDataSource;
compositeDisposable = new CompositeDisposable();
}
@ -43,19 +49,44 @@ public class ContributionsListPresenter implements UserActionListener {
* the live data object. This method can be tweaked to update the lazy loading behavior of the
* contributions list
*/
void setup() {
void setup(String userName, boolean isSelf) {
final PagedList.Config pagedListConfig =
(new PagedList.Config.Builder())
.setPrefetchDistance(50)
.setPageSize(10).build();
contributionList = (new LivePagedListBuilder(repository.fetchContributions(),
pagedListConfig)
.setBoundaryCallback(contributionBoundaryCallback)).build();
Factory<Integer, Contribution> factory;
boolean shouldSetBoundaryCallback;
if (!isSelf) {
//We don't want to persist contributions for other user's, therefore
// creating a new DataSource for them
contributionsRemoteDataSource.setUserName(userName);
factory = new Factory<Integer, Contribution>() {
@NonNull
@Override
public DataSource<Integer, Contribution> create() {
return contributionsRemoteDataSource;
}
};
shouldSetBoundaryCallback = false;
} else {
contributionBoundaryCallback.setUserName(userName);
shouldSetBoundaryCallback = true;
factory = repository.fetchContributions();
}
LivePagedListBuilder livePagedListBuilder = new LivePagedListBuilder(factory, pagedListConfig);
if (shouldSetBoundaryCallback) {
livePagedListBuilder.setBoundaryCallback(contributionBoundaryCallback);
}
contributionList = livePagedListBuilder.build();
}
@Override
public void onDetachView() {
compositeDisposable.clear();
contributionsRemoteDataSource.dispose();
contributionBoundaryCallback.dispose();
}
/**

View file

@ -0,0 +1,73 @@
package fr.free.nrw.commons.contributions
import androidx.paging.ItemKeyedDataSource
import fr.free.nrw.commons.di.CommonsApplicationModule
import fr.free.nrw.commons.media.MediaClient
import io.reactivex.Scheduler
import io.reactivex.disposables.CompositeDisposable
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Named
/**
* Data-Source which acts as mediator for contributions-data from the API
*/
class ContributionsRemoteDataSource @Inject constructor(
private val mediaClient: MediaClient,
@param:Named(CommonsApplicationModule.IO_THREAD) private val ioThreadScheduler: Scheduler
) : ItemKeyedDataSource<Int, Contribution>() {
private val compositeDisposable: CompositeDisposable = CompositeDisposable()
var userName: String? = null
override fun loadInitial(
params: LoadInitialParams<Int>,
callback: LoadInitialCallback<Contribution>
) {
fetchContributions(callback)
}
override fun loadAfter(
params: LoadParams<Int>,
callback: LoadCallback<Contribution>
) {
fetchContributions(callback)
}
override fun loadBefore(
params: LoadParams<Int>,
callback: LoadCallback<Contribution>
) {
}
override fun getKey(item: Contribution): Int {
return item.pageId.hashCode()
}
/**
* Fetches contributions using the MediaWiki API
*/
private fun fetchContributions(callback: LoadCallback<Contribution>) {
compositeDisposable.add(
mediaClient.getMediaListForUser(userName!!)
.map { mediaList ->
mediaList.map {
Contribution(media = it, state = Contribution.STATE_COMPLETED)
}
}
.subscribeOn(ioThreadScheduler)
.subscribe({
callback.onResult(it)
}) { error: Throwable ->
Timber.e(
"Failed to fetch contributions: %s",
error.message
)
}
)
}
fun dispose() {
compositeDisposable.dispose()
}
}

View file

@ -75,6 +75,7 @@ import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.nearby.Label;
import fr.free.nrw.commons.profile.ProfileActivity;
import fr.free.nrw.commons.ui.widget.HtmlTextView;
import fr.free.nrw.commons.utils.ViewUtilWrapper;
import io.reactivex.Single;
@ -1014,6 +1015,15 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
}
}
@OnClick(R.id.mediaDetailAuthor)
public void onAuthorViewClicked() {
if (media == null || media.getUser() == null) {
return;
}
ProfileActivity.startYourself(getActivity(), media.getUser(), !Objects
.equals(sessionManager.getUserName(), media.getUser()));
}
/**
* Enable Progress Bar and Update delete button text.
*/

View file

@ -32,6 +32,7 @@ import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
import fr.free.nrw.commons.profile.ProfileActivity;
import fr.free.nrw.commons.theme.BaseActivity;
import fr.free.nrw.commons.utils.DownloadUtils;
import fr.free.nrw.commons.utils.ImageUtils;
@ -201,6 +202,11 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
// Set avatar
setAvatar(m);
return true;
case R.id.menu_view_user_page:
if (m != null && m.getUser() != null) {
ProfileActivity.startYourself(getActivity(), m.getUser(),
!Objects.equals(sessionManager.getUserName(), m.getUser()));
}
default:
return super.onOptionsItemSelected(item);
}
@ -258,7 +264,9 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
menu.findItem(R.id.menu_download_current_image).setEnabled(true).setVisible(true);
menu.findItem(R.id.menu_bookmark_current_image).setEnabled(true).setVisible(true);
menu.findItem(R.id.menu_set_as_wallpaper).setEnabled(true).setVisible(true);
if (m.getUser() != null) {
menu.findItem(R.id.menu_view_user_page).setEnabled(true).setVisible(true);
}
// Initialize bookmark object
bookmark = new Bookmark(
m.getFilename(),

View file

@ -74,13 +74,20 @@ public class MoreBottomSheetFragment extends BottomSheetDialogFragment {
* Set the username in navigationHeader.
*/
private void setUserName() {
AccountManager accountManager = AccountManager.get(getActivity());
Account[] allAccounts = accountManager.getAccountsByType(BuildConfig.ACCOUNT_TYPE);
moreProfile.setText(getUserName());
}
private String getUserName(){
final AccountManager accountManager = AccountManager.get(getActivity());
final Account[] allAccounts = accountManager.getAccountsByType(BuildConfig.ACCOUNT_TYPE);
if (allAccounts.length != 0) {
moreProfile.setText(allAccounts[0].name);
return allAccounts[0].name;
}
return "";
}
@OnClick(R.id.more_logout)
public void onLogoutClicked() {
new AlertDialog.Builder(getActivity())
@ -136,9 +143,7 @@ public class MoreBottomSheetFragment extends BottomSheetDialogFragment {
@OnClick(R.id.more_profile)
public void onProfileClicked() {
final Intent intent = new Intent(getActivity(), ProfileActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
getActivity().startActivity(intent);
ProfileActivity.startYourself(getActivity(), getUserName(), false);
}
@OnClick(R.id.more_peer_review)

View file

@ -13,6 +13,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;
@ -25,6 +26,7 @@ import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.ViewPagerAdapter;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.contributions.ContributionsListFragment;
import fr.free.nrw.commons.profile.achievements.AchievementsFragment;
import fr.free.nrw.commons.profile.leaderboard.LeaderboardFragment;
import fr.free.nrw.commons.theme.BaseActivity;
@ -49,9 +51,6 @@ public class ProfileActivity extends BaseActivity {
@BindView(R.id.tab_layout)
TabLayout tabLayout;
@BindView(R.id.toolbar)
Toolbar toolbar;
@Inject
SessionManager sessionManager;
@ -59,15 +58,32 @@ public class ProfileActivity extends BaseActivity {
private AchievementsFragment achievementsFragment;
private LeaderboardFragment leaderboardFragment;
public static final String KEY_USERNAME ="username";
public static final String KEY_SHOULD_SHOW_CONTRIBUTIONS ="shouldShowContributions";
String userName;
private boolean shouldShowContributions;
@Override
protected void onRestoreInstanceState(final Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
userName = savedInstanceState.getString(KEY_USERNAME);
shouldShowContributions = savedInstanceState.getBoolean(KEY_SHOULD_SHOW_CONTRIBUTIONS);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTitle(sessionManager.getUserName());
userName = getIntent().getStringExtra(KEY_USERNAME);
shouldShowContributions = getIntent().getBooleanExtra(KEY_SHOULD_SHOW_CONTRIBUTIONS, false);
supportFragmentManager = getSupportFragmentManager();
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(viewPagerAdapter);
@ -87,11 +103,15 @@ public class ProfileActivity extends BaseActivity {
/**
* Creates a way to change current activity to AchievementActivity
*
* @param context
*/
public static void startYourself(Context context) {
public static void startYourself(final Context context, final String userName,
final boolean shouldShowContributions) {
Intent intent = new Intent(context, ProfileActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(KEY_USERNAME, userName);
intent.putExtra(KEY_SHOULD_SHOW_CONTRIBUTIONS, shouldShowContributions);
context.startActivity(intent);
}
@ -102,11 +122,28 @@ public class ProfileActivity extends BaseActivity {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
achievementsFragment = new AchievementsFragment();
Bundle achievementsBundle = new Bundle();
achievementsBundle.putString(KEY_USERNAME, userName);
achievementsFragment.setArguments(achievementsBundle);
fragmentList.add(achievementsFragment);
titleList.add(getResources().getString(R.string.achievements_tab_title).toUpperCase());
leaderboardFragment = new LeaderboardFragment();
Bundle leaderBoardBundle = new Bundle();
leaderBoardBundle.putString(KEY_USERNAME, userName);
leaderboardFragment.setArguments(leaderBoardBundle);
fragmentList.add(leaderboardFragment);
titleList.add(getResources().getString(R.string.leaderboard_tab_title).toUpperCase());
if (shouldShowContributions) {
ContributionsListFragment contributionsListFragment = new ContributionsListFragment();
Bundle contributionsListBundle = new Bundle();
contributionsListBundle.putString(KEY_USERNAME, userName);
contributionsListFragment.setArguments(contributionsListBundle);
fragmentList.add(contributionsListFragment);
titleList.add(getString(R.string.contributions_fragment).toUpperCase());
}
viewPagerAdapter.setTabData(fragmentList, titleList);
viewPagerAdapter.notifyDataSetChanged();
@ -191,4 +228,10 @@ public class ProfileActivity extends BaseActivity {
e.printStackTrace();
}
}
@Override
protected void onSaveInstanceState(@NonNull final Bundle outState) {
outState.putString(KEY_USERNAME, userName);
super.onSaveInstanceState(outState);
}
}

View file

@ -15,7 +15,9 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import butterknife.BindView;
@ -28,6 +30,7 @@ import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
import fr.free.nrw.commons.utils.ViewUtil;
import fr.free.nrw.commons.profile.ProfileActivity;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
@ -114,6 +117,9 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
@BindView(R.id.wikidata_edits)
TextView wikidataEditsText;
@BindView(R.id.tv_achievements_of_user)
AppCompatTextView tvAchievementsOfUser;
@Inject
SessionManager sessionManager;
@ -128,6 +134,16 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
// menu item for action bar
private MenuItem item;
private String userName;
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
userName = getArguments().getString(ProfileActivity.KEY_USERNAME);
}
}
/**
* This method helps in the creation Achievement screen and
* dynamically set the size of imageView
@ -157,6 +173,12 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
// Set the initial value of WikiData edits to 0
wikidataEditsText.setText("0");
if(sessionManager.getUserName().equals(userName)){
tvAchievementsOfUser.setVisibility(View.GONE);
}else{
tvAchievementsOfUser.setVisibility(View.VISIBLE);
tvAchievementsOfUser.setText(getString(R.string.achievements_of_user,userName));
}
setWikidataEditCount();
setAchievements();
return rootView;
@ -182,7 +204,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
try{
compositeDisposable.add(okHttpJsonApiClient
.getAchievements(Objects.requireNonNull(sessionManager.getCurrentAccount()).name)
.getAchievements(Objects.requireNonNull(userName))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
@ -225,7 +247,6 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
* in the form of JavaRx Single object<JSONobject>
*/
private void setWikidataEditCount() {
String userName = sessionManager.getUserName();
if (StringUtils.isBlank(userName)) {
return;
}
@ -274,7 +295,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
private void setUploadCount(Achievements achievements) {
if (checkAccount()) {
compositeDisposable.add(okHttpJsonApiClient
.getUploadCount(Objects.requireNonNull(sessionManager.getCurrentAccount()).name)
.getUploadCount(Objects.requireNonNull(userName))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
@ -304,7 +325,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
if (uploadCount==0){
setZeroAchievements();
}else {
imagesUploadedProgressbar.setVisibility(View.VISIBLE);
imagesUploadedProgressbar.setProgress
(100*uploadCount/levelInfo.getMaxUploadCount());
imagesUploadedProgressbar.setProgressTextFormatPattern
@ -314,10 +335,14 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
}
private void setZeroAchievements() {
AlertDialog.Builder builder=new AlertDialog.Builder(getActivity())
.setMessage(getString(R.string.no_achievements_yet))
.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
});
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setMessage(
!Objects.equals(sessionManager.getUserName(), userName) ?
getString(R.string.no_achievements_yet, userName) :
getString(R.string.you_have_no_achievements_yet)
)
.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
});
AlertDialog dialog = builder.create();
dialog.show();
imagesUploadedProgressbar.setVisibility(View.INVISIBLE);
@ -336,6 +361,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
* @param notRevertPercentage
*/
private void setImageRevertPercentage(int notRevertPercentage){
imageRevertsProgressbar.setVisibility(View.VISIBLE);
imageRevertsProgressbar.setProgress(notRevertPercentage);
String revertPercentage = Integer.toString(notRevertPercentage);
imageRevertsProgressbar.setProgressTextFormatPattern(revertPercentage + "%%");
@ -348,6 +374,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
* @param achievements
*/
private void inflateAchievements(Achievements achievements) {
imagesUsedByWikiProgressBar.setVisibility(View.VISIBLE);
thanksReceived.setText(String.valueOf(achievements.getThanksReceived()));
imagesUsedByWikiProgressBar.setProgress
(100 * achievements.getUniqueUsedImages() / levelInfo.getMaxUniqueImages());
@ -481,5 +508,4 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
}
return true;
}
}

View file

@ -17,6 +17,7 @@ import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.MergeAdapter;
@ -27,6 +28,7 @@ import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
import fr.free.nrw.commons.profile.ProfileActivity;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
@ -104,6 +106,16 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
*/
private boolean scrollToRank;
private String userName;
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
userName = getArguments().getString(ProfileActivity.KEY_USERNAME);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_leaderboard, container, false);
@ -220,7 +232,7 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
if (checkAccount()) {
try {
compositeDisposable.add(okHttpJsonApiClient
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
.getLeaderboard(Objects.requireNonNull(userName),
duration, category, null, null)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View file

@ -1,7 +1,7 @@
package fr.free.nrw.commons.profile.leaderboard;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.USER_LINK_PREFIX;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
@ -14,6 +14,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.facebook.drawee.view.SimpleDraweeView;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.profile.ProfileActivity;
/**
* This class extends RecyclerView.Adapter and creates the List section of the leaderboard
@ -81,9 +82,13 @@ public class LeaderboardListAdapter extends PagedListAdapter<LeaderboardList, Le
count.setText(getItem(position).getCategoryCount().toString());
/*
Open the user profile in a webview when a username is clicked on leaderboard
Now that we have our in app profile-section, lets take the user there
*/
holder.itemView.setOnClickListener(view -> Utils.handleWebUrl(holder.getContext(), Uri.parse(
String.format("%s%s", USER_LINK_PREFIX, getItem(position).getUsername()))));
holder.itemView.setOnClickListener(view -> {
if (view.getContext() instanceof ProfileActivity) {
((Activity) (view.getContext())).finish();
}
ProfileActivity.startYourself(view.getContext(), getItem(position).getUsername(), true);
});
}
}

View file

@ -15,8 +15,6 @@
android:layout_height="wrap_content"
android:background="?attr/mainBackground">
<include layout="@layout/toolbar"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"

View file

@ -15,6 +15,14 @@
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_achievements_of_user"
style="@style/MediaDetailTextLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
tools:text="Achievements of user : Ashish" />
<RelativeLayout
android:layout_width="match_parent"
@ -136,6 +144,7 @@
app:progress_start_color="#3A3381"
app:progress_stroke_width="@dimen/progressbar_stroke"
app:progress_text_format_pattern="573/110"
android:visibility="gone"
app:progress_text_color="@color/secondaryColor"
app:style="solid_line" />
@ -203,6 +212,7 @@
android:layout_marginRight="@dimen/large_gap"
android:layout_marginEnd="@dimen/large_gap"
android:progress="50"
android:visibility="gone"
android:id="@+id/image_reverts_progressbar"
app:progress_end_color="#8C8B98"
app:progress_start_color="#3A3381"
@ -270,6 +280,7 @@
app:progress_end_color="#8C8B98"
app:progress_start_color="#3A3381"
app:progress_stroke_width="2.5dp"
android:visibility="gone"
app:progress_text_color="@color/secondaryColor"
app:progress_text_format_pattern="12/24"
app:style="solid_line" />

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -26,11 +27,28 @@
android:layout_centerInParent="true"
android:visibility="gone"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/contributionsList"
android:layout_height="match_parent"
android:layout_width="match_parent"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_contributions_of_user"
style="@style/MediaDetailTextLabel"
tools:text="Contributions of user : Ashish"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
tools:visibility="visible"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/contributionsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/tv_contributions_of_user" />
</RelativeLayout>
<LinearLayout
android:id="@+id/fab_layout"

View file

@ -30,4 +30,9 @@
android:title="@string/menu_set_avatar"
app:showAsAction="never" />
<item
android:id="@+id/menu_view_user_page"
android:title="@string/menu_view_user_page"
app:showAsAction="never" />
</menu>

View file

@ -527,7 +527,8 @@ Upload your first media by tapping on the add button.</string>
<string name="coordinates_picking_unsuccessful">Unable to get coordinates.</string>
<string name="share_image_via">Share image via</string>
<string name="no_achievements_yet">You haven\'t made any contributions yet</string>
<string name="you_have_no_achievements_yet">You haven\'t made any contributions yet</string>
<string name="no_achievements_yet">%s has not made any contributions yet</string>
<string name="account_created">Account created!</string>
<string name="text_copy">Text copied to clipboard</string>
<string name="notification_mark_read">Notification marked as read</string>
@ -656,4 +657,7 @@ Upload your first media by tapping on the add button.</string>
<string name="learn_more">LEARN MORE</string>
<string name="wlm_campaign_title">Wiki Loves Monuments</string>
<string name="wlm_campaign_description">Wiki Loves Monuments is an international photo contest for monuments organised by Wikimedia</string>
<string name="contributions_of_user">Contributions of User: %s</string>
<string name="achievements_of_user">Achievements of User: %s</string>
<string name="menu_view_user_page">View user page</string>
</resources>

View file

@ -49,7 +49,8 @@ class ContributionBoundaryCallbackTest {
MockitoAnnotations.initMocks(this)
scheduler = Schedulers.trampoline()
contributionBoundaryCallback =
ContributionBoundaryCallback(repository, sessionManager, mediaClient, scheduler);
ContributionBoundaryCallback(repository, sessionManager, mediaClient, scheduler)
contributionBoundaryCallback.userName = "test"
}
@Test

View file

@ -32,6 +32,9 @@ class ContributionsListPresenterTest {
@Mock
internal lateinit var repository: ContributionsRepository
@Mock
internal lateinit var remoteDataSource: ContributionsRemoteDataSource
@Rule
@JvmField
var instantTaskExecutorRule = InstantTaskExecutorRule()
@ -49,7 +52,12 @@ class ContributionsListPresenterTest {
MockitoAnnotations.initMocks(this)
scheduler = Schedulers.trampoline()
contributionsListPresenter =
ContributionsListPresenter(contributionBoundaryCallback, repository, scheduler);
ContributionsListPresenter(
contributionBoundaryCallback,
remoteDataSource,
repository,
scheduler
);
}
@Test

View file

@ -80,7 +80,7 @@ class ProfileActivityTest {
@Test
@Throws(Exception::class)
fun testStartYourself() {
ProfileActivity.startYourself(activity)
ProfileActivity.startYourself(activity, "test", false)
}
@Test

View file

@ -11,12 +11,14 @@ import androidx.fragment.app.FragmentTransaction
import com.dinuscxj.progressbar.CircleProgressBar
import fr.free.nrw.commons.TestAppAdapter
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.profile.ProfileActivity
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.powermock.reflect.Whitebox
import org.robolectric.Robolectric
@ -85,6 +87,9 @@ class AchievementsFragmentUnitTests {
@Mock
private lateinit var progressBar: ProgressBar
@Mock
private lateinit var sessionManager: SessionManager
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@ -131,6 +136,10 @@ class AchievementsFragmentUnitTests {
Whitebox.setInternalState(fragment, "progressBar", progressBar)
Whitebox.setInternalState(fragment, "imagesRevertLimitText", imagesRevertLimitText)
Whitebox.setInternalState(fragment, "item", menuItem)
Whitebox.setInternalState(fragment, "sessionManager", sessionManager)
Mockito.`when`(sessionManager.userName).thenReturn("Test")
}
@Test