From 8b15863d7a5794be09308f0c3e592431b7c3a70b Mon Sep 17 00:00:00 2001 From: Madhur Gupta Date: Sat, 4 Jul 2020 20:59:42 +0530 Subject: [PATCH 1/2] =?UTF-8?q?Fixes=20#3861=20Use=20the=20APIs=20to=20fet?= =?UTF-8?q?ch=20leaderboard=E2=80=99s=20based=20on=20uploads=20via=20mobil?= =?UTF-8?q?e=20app=20(all=20time)=20and=20display=20it=20in=20the=20Leader?= =?UTF-8?q?board=20screen.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../free/nrw/commons/di/NetworkingModule.java | 10 ++ .../commons/mwapi/OkHttpJsonApiClient.java | 43 ++++++ .../leaderboard/LeaderboardFragment.java | 144 ++++++++++++++++++ .../profile/leaderboard/LeaderboardList.java | 53 +++++++ .../leaderboard/LeaderboardListAdapter.java | 73 +++++++++ .../leaderboard/LeaderboardResponse.java | 120 +++++++++++++++ .../main/res/layout/fragment_leaderboard.xml | 110 ++++++++++++- .../res/layout/leaderboard_list_element.xml | 55 +++++++ app/src/main/res/values/strings.xml | 5 + 9 files changed, 610 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardList.java create mode 100644 app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListAdapter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardResponse.java create mode 100644 app/src/main/res/layout/leaderboard_list_element.xml diff --git a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java index 495a8d01ef..84fdfe53a8 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java @@ -85,11 +85,13 @@ public HttpLoggingInterceptor provideHttpLoggingInterceptor() { public OkHttpJsonApiClient provideOkHttpJsonApiClient(OkHttpClient okHttpClient, DepictsClient depictsClient, @Named("tools_forge") HttpUrl toolsForgeUrl, + @Named("test_tools_forge") HttpUrl testToolsForgeUrl, @Named("default_preferences") JsonKvStore defaultKvStore, Gson gson) { return new OkHttpJsonApiClient(okHttpClient, depictsClient, toolsForgeUrl, + testToolsForgeUrl, WIKIDATA_SPARQL_QUERY_URL, BuildConfig.WIKIMEDIA_CAMPAIGNS_URL, gson); @@ -124,6 +126,14 @@ public HttpUrl provideToolsForgeUrl() { return HttpUrl.parse(TOOLS_FORGE_URL); } + @Provides + @Named("test_tools_forge") + @NonNull + @SuppressWarnings("ConstantConditions") + public HttpUrl provideTestToolsForgeUrl() { + return HttpUrl.parse(TEST_TOOLS_FORGE_URL); + } + @Provides @Singleton @Named(NAMED_COMMONS_WIKI_SITE) diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java index eeaba0a73d..d07667b48b 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java @@ -11,6 +11,7 @@ import fr.free.nrw.commons.nearby.Place; import fr.free.nrw.commons.nearby.model.NearbyResponse; import fr.free.nrw.commons.nearby.model.NearbyResultItem; +import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse; import fr.free.nrw.commons.upload.FileUtils; import fr.free.nrw.commons.upload.structure.depictions.DepictedItem; import fr.free.nrw.commons.utils.ConfigUtils; @@ -40,6 +41,7 @@ public class OkHttpJsonApiClient { private final OkHttpClient okHttpClient; private final DepictsClient depictsClient; private final HttpUrl wikiMediaToolforgeUrl; + private final HttpUrl wikiMediaTestToolforgeUrl; private final String sparqlQueryUrl; private final String campaignsUrl; private final Gson gson; @@ -49,17 +51,58 @@ public class OkHttpJsonApiClient { public OkHttpJsonApiClient(OkHttpClient okHttpClient, DepictsClient depictsClient, HttpUrl wikiMediaToolforgeUrl, + HttpUrl wikiMediaTestToolforgeUrl, String sparqlQueryUrl, String campaignsUrl, Gson gson) { this.okHttpClient = okHttpClient; this.depictsClient = depictsClient; this.wikiMediaToolforgeUrl = wikiMediaToolforgeUrl; + this.wikiMediaTestToolforgeUrl = wikiMediaTestToolforgeUrl; this.sparqlQueryUrl = sparqlQueryUrl; this.campaignsUrl = campaignsUrl; this.gson = gson; } + @NonNull + public Single getLeaderboard(String userName, String duration, String category, String limit, String offset) { + final String fetchLeaderboardUrlTemplate = wikiMediaTestToolforgeUrl + + "/leaderboard.py"; + return Single.fromCallable(() -> { + String url = String.format(Locale.ENGLISH, + fetchLeaderboardUrlTemplate, + userName, + duration, + category, + limit, + offset); + HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); + urlBuilder.addQueryParameter("user", userName); + urlBuilder.addQueryParameter("duration", duration); + urlBuilder.addQueryParameter("category", category); + urlBuilder.addQueryParameter("limit", limit); + urlBuilder.addQueryParameter("offset", offset); + Timber.i("Url %s", urlBuilder.toString()); + Request request = new Request.Builder() + .url(urlBuilder.toString()) + .build(); + Response response = okHttpClient.newCall(request).execute(); + if (response != null && response.body() != null && response.isSuccessful()) { + String json = response.body().string(); + if (json == null) { + return null; + } + Timber.d("Response for leaderboard is %s", json); + try { + return gson.fromJson(json, LeaderboardResponse.class); + } catch (Exception e) { + return new LeaderboardResponse(); + } + } + return null; + }); + } + @NonNull public Single getUploadCount(String userName) { HttpUrl.Builder urlBuilder = wikiMediaToolforgeUrl.newBuilder(); diff --git a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardFragment.java b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardFragment.java index 76cbc51a3b..e536a950ad 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardFragment.java @@ -1,18 +1,162 @@ package fr.free.nrw.commons.profile.leaderboard; +import android.accounts.Account; +import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; +import butterknife.ButterKnife; +import com.facebook.drawee.view.SimpleDraweeView; 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.utils.ViewUtil; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; +import java.util.List; +import java.util.Objects; +import javax.inject.Inject; +import timber.log.Timber; public class LeaderboardFragment extends CommonsDaggerSupportFragment { + @BindView(R.id.avatar) + SimpleDraweeView avatar; + + @BindView(R.id.username) + TextView username; + + @BindView(R.id.rank) + TextView rank; + + @BindView(R.id.count) + TextView count; + + @BindView(R.id.leaderboard_list) + RecyclerView leaderboardListRecyclerView; + + @BindView(R.id.progressBar) + ProgressBar progressBar; + + @Inject + SessionManager sessionManager; + + @Inject + OkHttpJsonApiClient okHttpJsonApiClient; + + private String avatarSourceURL = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/%s/1024px-%s.png"; + + private CompositeDisposable compositeDisposable = new CompositeDisposable(); + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_leaderboard, container, false); + ButterKnife.bind(this, rootView); + progressBar.setVisibility(View.VISIBLE); + hideLayouts(); + setLeaderboard(); return rootView; } + /** + * To call the API to get results in form Single + * which then calls parseJson when results are fetched + */ + private void setLeaderboard() { + if (checkAccount()) { + try{ + compositeDisposable.add(okHttpJsonApiClient + .getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name, + "all_time", "upload", null, null) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + response -> { + if (response != null && response.getStatus() == 200) { + setLeaderboardUser(response); + setLeaderboardList(response.getLeaderboardList()); + } + }, + t -> { + Timber.e(t, "Fetching leaderboard statistics failed"); + onError(); + } + )); + } + catch (Exception e){ + Timber.d(e+"success"); + } + } + } + + private void setLeaderboardUser(LeaderboardResponse response) { + hideProgressBar(); + avatar.setImageURI( + Uri.parse(String.format(avatarSourceURL, response.getAvatar(), response.getAvatar()))); + username.setText(response.getUsername()); + rank.setText(String.format("%s %d", getString(R.string.rank_prefix), response.getRank())); + count.setText(String.format("%s %d", getString(R.string.count_prefix), response.getCategoryCount())); + } + + private void setLeaderboardList(List leaderboardList) { + LeaderboardListAdapter leaderboardListAdapter = new LeaderboardListAdapter(leaderboardList); + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); + leaderboardListRecyclerView.setLayoutManager(linearLayoutManager); + leaderboardListRecyclerView.setAdapter(leaderboardListAdapter); + } + + /** + * to hide progressbar + */ + private void hideProgressBar() { + if (progressBar != null) { + progressBar.setVisibility(View.GONE); + avatar.setVisibility(View.VISIBLE); + username.setVisibility(View.VISIBLE); + rank.setVisibility(View.VISIBLE); + leaderboardListRecyclerView.setVisibility(View.VISIBLE); + } + } + + /** + * used to hide the layouts while fetching results from api + */ + private void hideLayouts(){ + avatar.setVisibility(View.INVISIBLE); + username.setVisibility(View.INVISIBLE); + rank.setVisibility(View.INVISIBLE); + leaderboardListRecyclerView.setVisibility(View.INVISIBLE); + } + + /** + * check to ensure that user is logged in + * @return + */ + private boolean checkAccount(){ + Account currentAccount = sessionManager.getCurrentAccount(); + if (currentAccount == null) { + Timber.d("Current account is null"); + ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.user_not_logged_in)); + sessionManager.forceLogin(getActivity()); + return false; + } + return true; + } + + /** + * Shows a generic error toast when error occurs while loading leaderboard + */ + private void onError() { + ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.error_occurred)); + progressBar.setVisibility(View.GONE); + } + } diff --git a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardList.java b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardList.java new file mode 100644 index 0000000000..d6b86a22b9 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardList.java @@ -0,0 +1,53 @@ +package fr.free.nrw.commons.profile.leaderboard; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class LeaderboardList { + + @SerializedName("username") + @Expose + private String username; + @SerializedName("category_count") + @Expose + private Integer categoryCount; + @SerializedName("avatar") + @Expose + private String avatar; + @SerializedName("rank") + @Expose + private Integer rank; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Integer getCategoryCount() { + return categoryCount; + } + + public void setCategoryCount(Integer categoryCount) { + this.categoryCount = categoryCount; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public Integer getRank() { + return rank; + } + + public void setRank(Integer rank) { + this.rank = rank; + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListAdapter.java b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListAdapter.java new file mode 100644 index 0000000000..4a61a1cb19 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListAdapter.java @@ -0,0 +1,73 @@ +package fr.free.nrw.commons.profile.leaderboard; + +import android.content.Context; +import android.net.Uri; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import com.facebook.drawee.view.SimpleDraweeView; +import fr.free.nrw.commons.R; +import java.util.List; + +public class LeaderboardListAdapter extends RecyclerView.Adapter { + + private List leaderboardList; + + private String avatarSourceURL = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/%s/1024px-%s.png"; + + public class ListViewHolder extends RecyclerView.ViewHolder { + TextView rank; + SimpleDraweeView avatar; + TextView username; + TextView count; + + public ListViewHolder(View itemView) { + super(itemView); + this.rank = itemView.findViewById(R.id.user_rank); + this.avatar = itemView.findViewById(R.id.user_avatar); + this.username = itemView.findViewById(R.id.user_name); + this.count = itemView.findViewById(R.id.user_count); + } + + public Context getContext() { + return itemView.getContext(); + } + } + + public LeaderboardListAdapter(List leaderboardList) { + this.leaderboardList = leaderboardList; + } + + @NonNull + @Override + public LeaderboardListAdapter.ListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.leaderboard_list_element, parent, false); + + return new ListViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull LeaderboardListAdapter.ListViewHolder holder, int position) { + TextView rank = holder.rank; + SimpleDraweeView avatar = holder.avatar; + TextView username = holder.username; + TextView count = holder.count; + + rank.setText(leaderboardList.get(position).getRank().toString()); + + avatar.setImageURI( + Uri.parse(String.format(avatarSourceURL, leaderboardList.get(position).getAvatar(), + leaderboardList.get(position).getAvatar()))); + username.setText(leaderboardList.get(position).getUsername()); + count.setText(leaderboardList.get(position).getCategoryCount().toString()); + } + + @Override + public int getItemCount() { + return leaderboardList.size(); + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardResponse.java b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardResponse.java new file mode 100644 index 0000000000..6624ebfd06 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardResponse.java @@ -0,0 +1,120 @@ +package fr.free.nrw.commons.profile.leaderboard; + +import java.util.List; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class LeaderboardResponse { + + @SerializedName("status") + @Expose + private Integer status; + @SerializedName("username") + @Expose + private String username; + @SerializedName("category_count") + @Expose + private Integer categoryCount; + @SerializedName("limit") + @Expose + private Object limit; + @SerializedName("avatar") + @Expose + private String avatar; + @SerializedName("offset") + @Expose + private Object offset; + @SerializedName("duration") + @Expose + private String duration; + @SerializedName("leaderboard_list") + @Expose + private List leaderboardList = null; + @SerializedName("category") + @Expose + private String category; + @SerializedName("rank") + @Expose + private Integer rank; + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Integer getCategoryCount() { + return categoryCount; + } + + public void setCategoryCount(Integer categoryCount) { + this.categoryCount = categoryCount; + } + + public Object getLimit() { + return limit; + } + + public void setLimit(Object limit) { + this.limit = limit; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public Object getOffset() { + return offset; + } + + public void setOffset(Object offset) { + this.offset = offset; + } + + public String getDuration() { + return duration; + } + + public void setDuration(String duration) { + this.duration = duration; + } + + public List getLeaderboardList() { + return leaderboardList; + } + + public void setLeaderboardList(List leaderboardList) { + this.leaderboardList = leaderboardList; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public Integer getRank() { + return rank; + } + + public void setRank(Integer rank) { + this.rank = rank; + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_leaderboard.xml b/app/src/main/res/layout/fragment_leaderboard.xml index 28f5b725cc..b965e83db2 100644 --- a/app/src/main/res/layout/fragment_leaderboard.xml +++ b/app/src/main/res/layout/fragment_leaderboard.xml @@ -1,6 +1,110 @@ - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/leaderboard_list_element.xml b/app/src/main/res/layout/leaderboard_list_element.xml new file mode 100644 index 0000000000..d779fe32a9 --- /dev/null +++ b/app/src/main/res/layout/leaderboard_list_element.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6f2a3a0c6a..64459cbf64 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -651,4 +651,9 @@ Upload your first media by tapping on the add button. Copy wikicode to clipboard Achievements Leaderboard + Rank: + Count: + Rank + User + Count From bbb9f58e9e7999f814ca7b9ea617a1f36daf5114 Mon Sep 17 00:00:00 2001 From: Madhur Gupta Date: Mon, 3 Aug 2020 22:18:07 +0530 Subject: [PATCH 2/2] Added option to set a new avatar --- .../media/MediaDetailPagerFragment.java | 30 ++++++++ .../commons/mwapi/OkHttpJsonApiClient.java | 33 ++++++++ .../leaderboard/LeaderboardConstants.java | 2 - .../leaderboard/LeaderboardListAdapter.java | 6 +- .../leaderboard/UpdateAvatarResponse.java | 44 +++++++++++ .../leaderboard/UserDetailAdapter.java | 5 +- .../fr/free/nrw/commons/utils/ImageUtils.java | 76 ++++++++++++++++--- .../main/res/menu/fragment_image_detail.xml | 4 + app/src/main/res/values/strings.xml | 5 ++ 9 files changed, 182 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/profile/leaderboard/UpdateAvatarResponse.java diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index f98e66db3b..f0d080beca 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -22,15 +22,19 @@ import com.google.android.material.snackbar.Snackbar; import fr.free.nrw.commons.Media; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.bookmarks.Bookmark; import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider; import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao; import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; +import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient; import fr.free.nrw.commons.utils.DownloadUtils; import fr.free.nrw.commons.utils.ImageUtils; import fr.free.nrw.commons.utils.NetworkUtils; import fr.free.nrw.commons.utils.ViewUtil; +import io.reactivex.disposables.CompositeDisposable; +import java.util.Objects; import javax.inject.Inject; import timber.log.Timber; @@ -38,6 +42,14 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple @Inject BookmarkPicturesDao bookmarkDao; + @Inject + OkHttpJsonApiClient okHttpJsonApiClient; + + @Inject + SessionManager sessionManager; + + private static CompositeDisposable compositeDisposable = new CompositeDisposable(); + @BindView(R.id.mediaDetailsPager) ViewPager pager; private Boolean editable; private boolean isFeaturedImage; @@ -159,6 +171,10 @@ public boolean onOptionsItemSelected(MenuItem item) { // Set wallpaper setWallpaper(m); return true; + case R.id.menu_set_as_avatar: + // Set avatar + setAvatar(m); + return true; default: return super.onOptionsItemSelected(item); } @@ -177,6 +193,20 @@ private void setWallpaper(Media media) { ImageUtils.setWallpaperFromImageUrl(getActivity(), Uri.parse(media.getImageUrl())); } + /** + * Set the media as user's leaderboard avatar + * @param media + */ + private void setAvatar(Media media) { + if (media.getImageUrl() == null || media.getImageUrl().isEmpty()) { + Timber.d("Media URL not present"); + return; + } + ImageUtils.setAvatarFromImageUrl(getActivity(), media.getImageUrl(), + Objects.requireNonNull(sessionManager.getCurrentAccount()).name, + okHttpJsonApiClient, compositeDisposable); + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { if (!editable) { // Disable menu options for editable views diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java index e7e12ddeff..e27d76614f 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java @@ -12,6 +12,7 @@ import fr.free.nrw.commons.profile.achievements.FeaturedImages; import fr.free.nrw.commons.profile.achievements.FeedbackResponse; import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse; +import fr.free.nrw.commons.profile.leaderboard.UpdateAvatarResponse; import fr.free.nrw.commons.upload.FileUtils; import fr.free.nrw.commons.upload.structure.depictions.DepictedItem; import fr.free.nrw.commons.utils.ConfigUtils; @@ -103,6 +104,38 @@ public Observable getLeaderboard(String userName, String du }); } + @NonNull + public Single setAvatar(String username, String avatar) { + final String urlTemplate = wikiMediaTestToolforgeUrl + + "/update_avatar.py"; + return Single.fromCallable(() -> { + String url = String.format(Locale.ENGLISH, + urlTemplate, + username, + avatar); + HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); + urlBuilder.addQueryParameter("user", username); + urlBuilder.addQueryParameter("avatar", avatar); + Timber.i("Url %s", urlBuilder.toString()); + Request request = new Request.Builder() + .url(urlBuilder.toString()) + .build(); + Response response = okHttpClient.newCall(request).execute(); + if (response != null && response.body() != null && response.isSuccessful()) { + String json = response.body().string(); + if (json == null) { + return null; + } + try { + return gson.fromJson(json, UpdateAvatarResponse.class); + } catch (Exception e) { + return new UpdateAvatarResponse(); + } + } + return null; + }); + } + @NonNull public Single getUploadCount(String userName) { HttpUrl.Builder urlBuilder = wikiMediaToolforgeUrl.newBuilder(); diff --git a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardConstants.java b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardConstants.java index 79b53ef98b..e31062db64 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardConstants.java +++ b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardConstants.java @@ -6,8 +6,6 @@ public class LeaderboardConstants { public static final int START_OFFSET = 0; - public static final String AVATAR_SOURCE_URL = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/%s/1024px-%s.png"; - public final static String LOADING = "Loading"; public final static String LOADED = "Loaded"; diff --git a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListAdapter.java b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListAdapter.java index c6318f9b26..eb8f4c234c 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListAdapter.java @@ -1,7 +1,5 @@ package fr.free.nrw.commons.profile.leaderboard; -import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.AVATAR_SOURCE_URL; - import android.content.Context; import android.net.Uri; import android.view.LayoutInflater; @@ -72,9 +70,7 @@ public void onBindViewHolder(@NonNull LeaderboardListAdapter.ListViewHolder hold rank.setText(getItem(position).getRank().toString()); - avatar.setImageURI( - Uri.parse(String.format(AVATAR_SOURCE_URL, getItem(position).getAvatar(), - getItem(position).getAvatar()))); + avatar.setImageURI(Uri.parse(getItem(position).getAvatar())); username.setText(getItem(position).getUsername()); count.setText(getItem(position).getCategoryCount().toString()); } diff --git a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/UpdateAvatarResponse.java b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/UpdateAvatarResponse.java new file mode 100644 index 0000000000..65e98ab6c6 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/UpdateAvatarResponse.java @@ -0,0 +1,44 @@ +package fr.free.nrw.commons.profile.leaderboard; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class UpdateAvatarResponse { + + @SerializedName("status") + @Expose + private String status; + + @SerializedName("message") + @Expose + private String message; + + @SerializedName("user") + @Expose + private String user; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + +} diff --git a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/UserDetailAdapter.java b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/UserDetailAdapter.java index 6604812194..631126540b 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/UserDetailAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/profile/leaderboard/UserDetailAdapter.java @@ -1,7 +1,5 @@ package fr.free.nrw.commons.profile.leaderboard; -import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.AVATAR_SOURCE_URL; - import android.content.Context; import android.net.Uri; import android.view.LayoutInflater; @@ -62,8 +60,7 @@ public void onBindViewHolder(@NonNull UserDetailAdapter.DataViewHolder holder, i leaderboardResponse.getRank())); avatar.setImageURI( - Uri.parse(String.format(AVATAR_SOURCE_URL, leaderboardResponse.getAvatar(), - leaderboardResponse.getAvatar()))); + Uri.parse(leaderboardResponse.getAvatar())); username.setText(leaderboardResponse.getUsername()); count.setText(String.format("%s %d", holder.getContext().getResources().getString(R.string.count_prefix), diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java index f118164bf7..17ec834123 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java @@ -7,11 +7,9 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.net.Uri; - import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.exifinterface.media.ExifInterface; - import com.facebook.common.executors.CallerThreadExecutor; import com.facebook.common.references.CloseableReference; import com.facebook.datasource.DataSource; @@ -21,13 +19,15 @@ import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; - +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.location.LatLng; +import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; - -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.location.LatLng; import timber.log.Timber; /** @@ -69,7 +69,9 @@ public class ImageUtils { public static final int FILE_NAME_EXISTS = -4; static final int NO_CATEGORY_SELECTED = -5; - private static ProgressDialog progressDialog; + private static ProgressDialog progressDialogWallpaper; + + private static ProgressDialog progressDialogAvatar; @IntDef( flag = true, @@ -223,28 +225,78 @@ public void onFailureImpl(DataSource dataSource) { }, CallerThreadExecutor.getInstance()); } + /** + * Calls the set avatar api to set the image url as user's avatar + * @param context + * @param url + * @param username + * @param okHttpJsonApiClient + * @param compositeDisposable + */ + public static void setAvatarFromImageUrl(Context context, String url, String username, + OkHttpJsonApiClient okHttpJsonApiClient, CompositeDisposable compositeDisposable) { + showSettingAvatarProgressBar(context); + + try { + compositeDisposable.add(okHttpJsonApiClient + .setAvatar(username, url) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + response -> { + if (response != null && response.getStatus().equals("200")) { + ViewUtil.showLongToast(context, context.getString(R.string.avatar_set_successfully)); + if (progressDialogAvatar != null && progressDialogAvatar.isShowing()) { + progressDialogAvatar.dismiss(); + } + } + }, + t -> { + Timber.e(t, "Setting Avatar Failed"); + ViewUtil.showLongToast(context, context.getString(R.string.avatar_set_unsuccessfully)); + if (progressDialogAvatar != null) { + progressDialogAvatar.cancel(); + } + } + )); + } + catch (Exception e){ + Timber.d(e+"success"); + ViewUtil.showLongToast(context, context.getString(R.string.avatar_set_unsuccessfully)); + if (progressDialogAvatar != null) { + progressDialogAvatar.cancel(); + } + } + + } + private static void setWallpaper(Context context, Bitmap bitmap) { WallpaperManager wallpaperManager = WallpaperManager.getInstance(context); try { wallpaperManager.setBitmap(bitmap); ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_successfully)); - if (progressDialog != null && progressDialog.isShowing()) { - progressDialog.dismiss(); + if (progressDialogWallpaper != null && progressDialogWallpaper.isShowing()) { + progressDialogWallpaper.dismiss(); } } catch (IOException e) { Timber.e(e, "Error setting wallpaper"); ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_unsuccessfully)); - if (progressDialog != null) { - progressDialog.cancel(); + if (progressDialogWallpaper != null) { + progressDialogWallpaper.cancel(); } } } private static void showSettingWallpaperProgressBar(Context context) { - progressDialog = ProgressDialog.show(context, context.getString(R.string.setting_wallpaper_dialog_title), + progressDialogWallpaper = ProgressDialog.show(context, context.getString(R.string.setting_wallpaper_dialog_title), context.getString(R.string.setting_wallpaper_dialog_message), true); } + private static void showSettingAvatarProgressBar(Context context) { + progressDialogAvatar = ProgressDialog.show(context, context.getString(R.string.setting_avatar_dialog_title), + context.getString(R.string.setting_avatar_dialog_message), true); + } + /** * Result variable is a result of an or operation of all possible problems. Ie. if result * is 0001 means IMAGE_DARK diff --git a/app/src/main/res/menu/fragment_image_detail.xml b/app/src/main/res/menu/fragment_image_detail.xml index 21f5f9be97..7339834a1d 100644 --- a/app/src/main/res/menu/fragment_image_detail.xml +++ b/app/src/main/res/menu/fragment_image_detail.xml @@ -25,5 +25,9 @@ android:id="@+id/menu_set_as_wallpaper" android:title="@string/menu_set_wallpaper" app:showAsAction="never" /> + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 64459cbf64..2cfeec0728 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -656,4 +656,9 @@ Upload your first media by tapping on the add button. Rank User Count + Set as Leaderboard Avatar + Setting as Avatar, please wait + Avatar Set Successfully + Error setting new avatar, please try again + Set as avatar