mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
[GSoC] Added option to set a new avatar (#3892)
* Fixes #3861 Use the APIs to fetch leaderboard’s based on uploads via mobile app (all time) and display it in the Leaderboard screen. * Added option to set a new avatar
This commit is contained in:
parent
5f77f610f5
commit
bc0b5c05c7
9 changed files with 182 additions and 23 deletions
|
|
@ -22,15 +22,19 @@ import butterknife.ButterKnife;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import fr.free.nrw.commons.Media;
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.R;
|
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.Bookmark;
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
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.DownloadUtils;
|
||||||
import fr.free.nrw.commons.utils.ImageUtils;
|
import fr.free.nrw.commons.utils.ImageUtils;
|
||||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import java.util.Objects;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
@ -38,6 +42,14 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
||||||
|
|
||||||
@Inject BookmarkPicturesDao bookmarkDao;
|
@Inject BookmarkPicturesDao bookmarkDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
OkHttpJsonApiClient okHttpJsonApiClient;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SessionManager sessionManager;
|
||||||
|
|
||||||
|
private static CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||||
|
|
||||||
@BindView(R.id.mediaDetailsPager) ViewPager pager;
|
@BindView(R.id.mediaDetailsPager) ViewPager pager;
|
||||||
private Boolean editable;
|
private Boolean editable;
|
||||||
private boolean isFeaturedImage;
|
private boolean isFeaturedImage;
|
||||||
|
|
@ -159,6 +171,10 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
||||||
// Set wallpaper
|
// Set wallpaper
|
||||||
setWallpaper(m);
|
setWallpaper(m);
|
||||||
return true;
|
return true;
|
||||||
|
case R.id.menu_set_as_avatar:
|
||||||
|
// Set avatar
|
||||||
|
setAvatar(m);
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
@ -177,6 +193,20 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
||||||
ImageUtils.setWallpaperFromImageUrl(getActivity(), Uri.parse(media.getImageUrl()));
|
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
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
if (!editable) { // Disable menu options for editable views
|
if (!editable) { // Disable menu options for editable views
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import fr.free.nrw.commons.nearby.model.NearbyResultItem;
|
||||||
import fr.free.nrw.commons.profile.achievements.FeaturedImages;
|
import fr.free.nrw.commons.profile.achievements.FeaturedImages;
|
||||||
import fr.free.nrw.commons.profile.achievements.FeedbackResponse;
|
import fr.free.nrw.commons.profile.achievements.FeedbackResponse;
|
||||||
import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse;
|
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.FileUtils;
|
||||||
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||||
|
|
@ -103,6 +104,38 @@ public class OkHttpJsonApiClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Single<UpdateAvatarResponse> 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
|
@NonNull
|
||||||
public Single<Integer> getUploadCount(String userName) {
|
public Single<Integer> getUploadCount(String userName) {
|
||||||
HttpUrl.Builder urlBuilder = wikiMediaToolforgeUrl.newBuilder();
|
HttpUrl.Builder urlBuilder = wikiMediaToolforgeUrl.newBuilder();
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@ public class LeaderboardConstants {
|
||||||
|
|
||||||
public static final int START_OFFSET = 0;
|
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 LOADING = "Loading";
|
||||||
|
|
||||||
public final static String LOADED = "Loaded";
|
public final static String LOADED = "Loaded";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package fr.free.nrw.commons.profile.leaderboard;
|
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.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
|
@ -72,9 +70,7 @@ public class LeaderboardListAdapter extends PagedListAdapter<LeaderboardList, Le
|
||||||
|
|
||||||
rank.setText(getItem(position).getRank().toString());
|
rank.setText(getItem(position).getRank().toString());
|
||||||
|
|
||||||
avatar.setImageURI(
|
avatar.setImageURI(Uri.parse(getItem(position).getAvatar()));
|
||||||
Uri.parse(String.format(AVATAR_SOURCE_URL, getItem(position).getAvatar(),
|
|
||||||
getItem(position).getAvatar())));
|
|
||||||
username.setText(getItem(position).getUsername());
|
username.setText(getItem(position).getUsername());
|
||||||
count.setText(getItem(position).getCategoryCount().toString());
|
count.setText(getItem(position).getCategoryCount().toString());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package fr.free.nrw.commons.profile.leaderboard;
|
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.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
|
@ -62,8 +60,7 @@ public class UserDetailAdapter extends RecyclerView.Adapter<UserDetailAdapter.Da
|
||||||
leaderboardResponse.getRank()));
|
leaderboardResponse.getRank()));
|
||||||
|
|
||||||
avatar.setImageURI(
|
avatar.setImageURI(
|
||||||
Uri.parse(String.format(AVATAR_SOURCE_URL, leaderboardResponse.getAvatar(),
|
Uri.parse(leaderboardResponse.getAvatar()));
|
||||||
leaderboardResponse.getAvatar())));
|
|
||||||
username.setText(leaderboardResponse.getUsername());
|
username.setText(leaderboardResponse.getUsername());
|
||||||
count.setText(String.format("%s %d",
|
count.setText(String.format("%s %d",
|
||||||
holder.getContext().getResources().getString(R.string.count_prefix),
|
holder.getContext().getResources().getString(R.string.count_prefix),
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,9 @@ import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.exifinterface.media.ExifInterface;
|
import androidx.exifinterface.media.ExifInterface;
|
||||||
|
|
||||||
import com.facebook.common.executors.CallerThreadExecutor;
|
import com.facebook.common.executors.CallerThreadExecutor;
|
||||||
import com.facebook.common.references.CloseableReference;
|
import com.facebook.common.references.CloseableReference;
|
||||||
import com.facebook.datasource.DataSource;
|
import com.facebook.datasource.DataSource;
|
||||||
|
|
@ -21,13 +19,15 @@ import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
|
||||||
import com.facebook.imagepipeline.image.CloseableImage;
|
import com.facebook.imagepipeline.image.CloseableImage;
|
||||||
import com.facebook.imagepipeline.request.ImageRequest;
|
import com.facebook.imagepipeline.request.ImageRequest;
|
||||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
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.io.IOException;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -69,7 +69,9 @@ public class ImageUtils {
|
||||||
public static final int FILE_NAME_EXISTS = -4;
|
public static final int FILE_NAME_EXISTS = -4;
|
||||||
static final int NO_CATEGORY_SELECTED = -5;
|
static final int NO_CATEGORY_SELECTED = -5;
|
||||||
|
|
||||||
private static ProgressDialog progressDialog;
|
private static ProgressDialog progressDialogWallpaper;
|
||||||
|
|
||||||
|
private static ProgressDialog progressDialogAvatar;
|
||||||
|
|
||||||
@IntDef(
|
@IntDef(
|
||||||
flag = true,
|
flag = true,
|
||||||
|
|
@ -223,28 +225,78 @@ public class ImageUtils {
|
||||||
}, CallerThreadExecutor.getInstance());
|
}, 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) {
|
private static void setWallpaper(Context context, Bitmap bitmap) {
|
||||||
WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
|
WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
|
||||||
try {
|
try {
|
||||||
wallpaperManager.setBitmap(bitmap);
|
wallpaperManager.setBitmap(bitmap);
|
||||||
ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_successfully));
|
ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_successfully));
|
||||||
if (progressDialog != null && progressDialog.isShowing()) {
|
if (progressDialogWallpaper != null && progressDialogWallpaper.isShowing()) {
|
||||||
progressDialog.dismiss();
|
progressDialogWallpaper.dismiss();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Timber.e(e, "Error setting wallpaper");
|
Timber.e(e, "Error setting wallpaper");
|
||||||
ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_unsuccessfully));
|
ViewUtil.showLongToast(context, context.getString(R.string.wallpaper_set_unsuccessfully));
|
||||||
if (progressDialog != null) {
|
if (progressDialogWallpaper != null) {
|
||||||
progressDialog.cancel();
|
progressDialogWallpaper.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void showSettingWallpaperProgressBar(Context context) {
|
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);
|
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
|
* Result variable is a result of an or operation of all possible problems. Ie. if result
|
||||||
* is 0001 means IMAGE_DARK
|
* is 0001 means IMAGE_DARK
|
||||||
|
|
|
||||||
|
|
@ -25,5 +25,9 @@
|
||||||
android:id="@+id/menu_set_as_wallpaper"
|
android:id="@+id/menu_set_as_wallpaper"
|
||||||
android:title="@string/menu_set_wallpaper"
|
android:title="@string/menu_set_wallpaper"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_set_as_avatar"
|
||||||
|
android:title="@string/menu_set_avatar"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
@ -656,4 +656,9 @@ Upload your first media by tapping on the add button.</string>
|
||||||
<string name="leaderboard_column_rank">Rank</string>
|
<string name="leaderboard_column_rank">Rank</string>
|
||||||
<string name="leaderboard_column_user">User</string>
|
<string name="leaderboard_column_user">User</string>
|
||||||
<string name="leaderboard_column_count">Count</string>
|
<string name="leaderboard_column_count">Count</string>
|
||||||
|
<string name="setting_avatar_dialog_title">Set as Leaderboard Avatar</string>
|
||||||
|
<string name="setting_avatar_dialog_message">Setting as Avatar, please wait</string>
|
||||||
|
<string name="avatar_set_successfully">Avatar Set Successfully</string>
|
||||||
|
<string name="avatar_set_unsuccessfully">Error setting new avatar, please try again</string>
|
||||||
|
<string name="menu_set_avatar">Set as avatar</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue