mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
Feedback module (#1742)
* Implemented Statistics * Basic Structure Implemented * Layout made screen independent and menu inflated * Share Screenshot using cache * Improved the Image Bound and added strings * Improved the quality of Pr * Wired to navigation drawer * Changed the bounds of the image * Added Info icon * Removed the unecessary functionality * Updated JavaDocs and fetch the username * Fetch JsonObject from the api using JavaRx and OkHttp * Added JavaDocs and improved quality * fixed strings file * Improved the quality of pr * Render thanks , images used in articles on screen * fetch and rendered the upload count * FeaturedImages statistics rendered and Javadocs added * added ProgressBar * Added Class for calculating level * added level info and returned level info * level up info rendered on achievement activity * Inflated Level Number * Added the structure for badge * Added LevelUpInfo Programmetically on Drawable * aligned the text * changed the text * Implemented the structure for changing colour of drawable * Added functionality to change colours of badge during runtime * Added custom alert for share option * Improved the UI of screen * Added the alertDialog for info button * Improved the quality of PR * Added Builder model * Added Enum Model and increased levels to 15 * removed redundant class * Changed strings and added subtext * Feedback Module: Add reverts rate parameter (#1649) * Fetched Revert Count * Refactored Achievements class and display the fetched results * Refactored the levelController to include revert as parameter * Fixed error * Fixed bug * Added information for parameters and improved code quality * Javadocs added * Added null check and javadocs * Removed extra spaces
This commit is contained in:
parent
86878fb62d
commit
e9c0aa22ea
25 changed files with 2456 additions and 17 deletions
|
|
@ -2,11 +2,13 @@ package fr.free.nrw.commons;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
|
@ -150,7 +152,7 @@ public class Utils {
|
|||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
try {
|
||||
String[] command = new String[] {"logcat","-d","-v","threadtime"};
|
||||
String[] command = new String[]{"logcat","-d","-v","threadtime"};
|
||||
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
|
||||
|
|
@ -199,4 +201,18 @@ public class Utils {
|
|||
customTabsIntent.launchUrl(context, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* To take screenshot of the screen and return it in Bitmap format
|
||||
*
|
||||
* @param view
|
||||
* @return
|
||||
*/
|
||||
public static Bitmap getScreenShot(View view) {
|
||||
View screenView = view.getRootView();
|
||||
screenView.setDrawingCacheEnabled(true);
|
||||
Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
|
||||
screenView.setDrawingCacheEnabled(false);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,205 @@
|
|||
package fr.free.nrw.commons.achievements;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* represnts Achievements class ans stores all the parameters
|
||||
*/
|
||||
public class Achievements {
|
||||
private int uniqueUsedImages;
|
||||
private int articlesUsingImages;
|
||||
private int thanksReceived;
|
||||
private int imagesEditedBySomeoneElse;
|
||||
private int featuredImages;
|
||||
private int imagesUploaded;
|
||||
private int revertCount;
|
||||
|
||||
public Achievements(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor for achievements class to set its data members
|
||||
* @param uniqueUsedImages
|
||||
* @param articlesUsingImages
|
||||
* @param thanksReceived
|
||||
* @param imagesEditedBySomeoneElse
|
||||
* @param featuredImages
|
||||
* @param imagesUploaded
|
||||
* @param revertCount
|
||||
*/
|
||||
public Achievements(int uniqueUsedImages,
|
||||
int articlesUsingImages,
|
||||
int thanksReceived,
|
||||
int imagesEditedBySomeoneElse,
|
||||
int featuredImages,
|
||||
int imagesUploaded,
|
||||
int revertCount) {
|
||||
this.uniqueUsedImages = uniqueUsedImages;
|
||||
this.articlesUsingImages = articlesUsingImages;
|
||||
this.thanksReceived = thanksReceived;
|
||||
this.imagesEditedBySomeoneElse = imagesEditedBySomeoneElse;
|
||||
this.featuredImages = featuredImages;
|
||||
this.imagesUploaded = imagesUploaded;
|
||||
this.revertCount = revertCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for Achievements class
|
||||
*/
|
||||
public class AchievementsBuilder {
|
||||
private int nestedUniqueUsedImages;
|
||||
private int nestedArticlesUsingImages;
|
||||
private int nestedThanksReceived;
|
||||
private int nestedImagesEditedBySomeoneElse;
|
||||
private int nestedFeaturedImages;
|
||||
private int nestedImagesUploaded;
|
||||
private int nestedRevertCount;
|
||||
|
||||
public AchievementsBuilder setUniqueUsedImages(int uniqueUsedImages) {
|
||||
this.nestedUniqueUsedImages = uniqueUsedImages;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AchievementsBuilder setArticlesUsingImages(int articlesUsingImages) {
|
||||
this.nestedArticlesUsingImages = articlesUsingImages;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AchievementsBuilder setThanksReceived(int thanksReceived) {
|
||||
this.nestedThanksReceived = thanksReceived;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AchievementsBuilder setImagesEditedBySomeoneElse(int imagesEditedBySomeoneElse) {
|
||||
this.nestedImagesEditedBySomeoneElse = imagesEditedBySomeoneElse;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AchievementsBuilder setFeaturedImages(int featuredImages) {
|
||||
this.nestedFeaturedImages = featuredImages;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AchievementsBuilder setImagesUploaded(int imagesUploaded) {
|
||||
this.nestedImagesUploaded = imagesUploaded;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AchievementsBuilder setRevertCount( int revertCount){
|
||||
this.nestedRevertCount = revertCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Achievements createAchievements(){
|
||||
return new Achievements(nestedUniqueUsedImages,
|
||||
nestedArticlesUsingImages,
|
||||
nestedThanksReceived,
|
||||
nestedImagesEditedBySomeoneElse,
|
||||
nestedFeaturedImages,
|
||||
nestedImagesUploaded,
|
||||
nestedRevertCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* getter function to get count of images uploaded
|
||||
* @return
|
||||
*/
|
||||
public int getImagesUploaded() {
|
||||
return imagesUploaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter function to get count of featured images
|
||||
* @return
|
||||
*/
|
||||
public int getFeaturedImages() {
|
||||
return featuredImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter function to get count of thanks received
|
||||
* @return
|
||||
*/
|
||||
public int getThanksReceived() {
|
||||
return thanksReceived;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter function to get count of unique images used by wiki
|
||||
* @return
|
||||
*/
|
||||
public int getUniqueUsedImages() {
|
||||
return uniqueUsedImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter function to count of images uploaded
|
||||
* @param imagesUploaded
|
||||
*/
|
||||
public void setImagesUploaded(int imagesUploaded) {
|
||||
this.imagesUploaded = imagesUploaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter function to set count of featured images
|
||||
* @param featuredImages
|
||||
*/
|
||||
public void setFeaturedImages(int featuredImages) {
|
||||
this.featuredImages = featuredImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter function to set the count of images edited by someone
|
||||
* @param imagesEditedBySomeoneElse
|
||||
*/
|
||||
public void setImagesEditedBySomeoneElse(int imagesEditedBySomeoneElse) {
|
||||
this.imagesEditedBySomeoneElse = imagesEditedBySomeoneElse;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter function to set count of thanks received
|
||||
* @param thanksReceived
|
||||
*/
|
||||
public void setThanksReceived(int thanksReceived) {
|
||||
this.thanksReceived = thanksReceived;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter function to count of articles using images uploaded
|
||||
* @param articlesUsingImages
|
||||
*/
|
||||
public void setArticlesUsingImages(int articlesUsingImages) {
|
||||
this.articlesUsingImages = articlesUsingImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter function to set count of uniques images used by wiki
|
||||
* @param uniqueUsedImages
|
||||
*/
|
||||
public void setUniqueUsedImages(int uniqueUsedImages) {
|
||||
this.uniqueUsedImages = uniqueUsedImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* to set count of images reverted
|
||||
* @param revertCount
|
||||
*/
|
||||
public void setRevertCount(int revertCount) {
|
||||
this.revertCount = revertCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* used to calculate the percentages of images that haven't been reverted
|
||||
* @return
|
||||
*/
|
||||
public int getNotRevertPercentage(){
|
||||
try {
|
||||
return ((imagesUploaded - revertCount) * 100)/imagesUploaded;
|
||||
} catch (ArithmeticException divideByZero ){
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,458 @@
|
|||
package fr.free.nrw.commons.achievements;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.content.res.ResourcesCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.dinuscxj.progressbar.CircleProgressBar;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||
import fr.free.nrw.commons.theme.NavigationBaseActivity;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* activity for sharing feedback on uploaded activity
|
||||
*/
|
||||
public class AchievementsActivity extends NavigationBaseActivity {
|
||||
|
||||
private static final double BADGE_IMAGE_WIDTH_RATIO = 0.4;
|
||||
private static final double BADGE_IMAGE_HEIGHT_RATIO = 0.3;
|
||||
private Boolean isUploadFetched = false;
|
||||
private Boolean isStatisticsFetched = false;
|
||||
private Boolean isRevertFetched = false;
|
||||
private Achievements achievements = new Achievements();
|
||||
private LevelController.LevelInfo levelInfo;
|
||||
|
||||
@BindView(R.id.achievement_badge)
|
||||
ImageView imageView;
|
||||
@BindView(R.id.achievement_level)
|
||||
TextView levelNumber;
|
||||
@BindView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
@BindView(R.id.thanks_received)
|
||||
TextView thanksReceived;
|
||||
@BindView(R.id.images_uploaded_progressbar)
|
||||
CircleProgressBar imagesUploadedProgressbar;
|
||||
@BindView(R.id.images_used_by_wiki_progressbar)
|
||||
CircleProgressBar imagesUsedByWikiProgessbar;
|
||||
@BindView(R.id.image_reverts_progressbar)
|
||||
CircleProgressBar imageRevertsProgressbar;
|
||||
@BindView(R.id.image_featured)
|
||||
TextView imagesFeatured;
|
||||
@BindView(R.id.images_revert_limit_text)
|
||||
TextView imagesRevertLimitText;
|
||||
@BindView(R.id.progressBar)
|
||||
ProgressBar progressBar;
|
||||
@BindView(R.id.layout_image_uploaded)
|
||||
RelativeLayout layoutImageUploaded;
|
||||
@BindView(R.id.layout_image_reverts)
|
||||
RelativeLayout layoutImageReverts;
|
||||
@BindView(R.id.layout_image_used_by_wiki)
|
||||
RelativeLayout layoutImageUsedByWiki;
|
||||
@BindView(R.id.layout_statistics)
|
||||
LinearLayout layoutStatistics;
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
@Inject
|
||||
MediaWikiApi mediaWikiApi;
|
||||
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
/**
|
||||
* This method helps in the creation Achievement screen and
|
||||
* dynamically set the size of imageView
|
||||
*
|
||||
* @param savedInstanceState Data bundle
|
||||
*/
|
||||
@Override
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_achievements);
|
||||
ButterKnife.bind(this);
|
||||
/**
|
||||
* DisplayMetrics used to fetch the size of the screen
|
||||
*/
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||
int height = displayMetrics.heightPixels;
|
||||
int width = displayMetrics.widthPixels;
|
||||
|
||||
/**
|
||||
* Used for the setting the size of imageView at runtime
|
||||
*/
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)
|
||||
imageView.getLayoutParams();
|
||||
params.height = (int) (height * BADGE_IMAGE_HEIGHT_RATIO);
|
||||
params.width = (int) (width * BADGE_IMAGE_WIDTH_RATIO);
|
||||
imageView.setImageResource(R.drawable.badge);
|
||||
imageView.requestLayout();
|
||||
|
||||
setSupportActionBar(toolbar);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
hideLayouts();
|
||||
setAchievements();
|
||||
setUploadCount();
|
||||
setRevertCount();
|
||||
initDrawer();
|
||||
}
|
||||
|
||||
/**
|
||||
* to invoke the AlertDialog on clicking info button
|
||||
*/
|
||||
@OnClick(R.id.achievement_info)
|
||||
public void showInfoDialog(){
|
||||
launchAlert(getResources().getString(R.string.Achievements)
|
||||
,getResources().getString(R.string.achievements_info_message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_about, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if (id == R.id.share_app_icon) {
|
||||
View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
|
||||
Bitmap screenShot = Utils.getScreenShot(rootView);
|
||||
showAlert(screenShot);
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* To take bitmap and store it temporary storage and share it
|
||||
*
|
||||
* @param bitmap
|
||||
*/
|
||||
void shareScreen(Bitmap bitmap) {
|
||||
try {
|
||||
File file = new File(this.getExternalCacheDir(), "screen.png");
|
||||
FileOutputStream fOut = new FileOutputStream(file);
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
|
||||
fOut.flush();
|
||||
fOut.close();
|
||||
file.setReadable(true, false);
|
||||
final Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
|
||||
intent.setType("image/png");
|
||||
startActivity(Intent.createChooser(intent, "Share image via"));
|
||||
} catch (IOException e) {
|
||||
//Do Nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To call the API to get results in form Single<JSONObject>
|
||||
* which then calls parseJson when results are fetched
|
||||
*/
|
||||
private void setAchievements() {
|
||||
if(checkAccount()) {
|
||||
compositeDisposable.add(mediaWikiApi
|
||||
.getAchievements(sessionManager.getCurrentAccount().name)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
jsonObject -> parseJson(jsonObject),
|
||||
t -> Timber.e(t, "Fetching achievements statisticss failed")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To call the API to get reverts count in form of JSONObject
|
||||
*
|
||||
*/
|
||||
|
||||
private void setRevertCount(){
|
||||
if(checkAccount()) {
|
||||
compositeDisposable.add(mediaWikiApi
|
||||
.getRevertCount(sessionManager.getCurrentAccount().name)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
object -> parseJsonRevertCount(object),
|
||||
t -> Timber.e(t, "Fetching revert count failed")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* used to set number of deleted images
|
||||
* @param object
|
||||
*/
|
||||
private void parseJsonRevertCount(JSONObject object){
|
||||
try {
|
||||
achievements.setRevertCount(object.getInt("deletedUploads"));
|
||||
} catch (JSONException e) {
|
||||
Timber.d( e, e.getMessage());
|
||||
}
|
||||
isRevertFetched = true;
|
||||
hideProgressBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* used to the count of images uploaded by user
|
||||
*/
|
||||
private void setUploadCount() {
|
||||
if(checkAccount()) {
|
||||
compositeDisposable.add(mediaWikiApi
|
||||
.getUploadCount(sessionManager.getCurrentAccount().name)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
uploadCount -> setAchievementsUploadCount(uploadCount),
|
||||
t -> Timber.e(t, "Fetching upload count failed")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* used to set achievements upload count and call hideProgressbar
|
||||
* @param uploadCount
|
||||
*/
|
||||
private void setAchievementsUploadCount(int uploadCount){
|
||||
achievements.setImagesUploaded(uploadCount);
|
||||
isUploadFetched = true;
|
||||
hideProgressBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* used to the uploaded images progressbar
|
||||
* @param uploadCount
|
||||
*/
|
||||
private void setUploadProgress(int uploadCount){
|
||||
imagesUploadedProgressbar.setProgress
|
||||
(100*uploadCount/levelInfo.getMaxUploadCount());
|
||||
imagesUploadedProgressbar.setProgressTextFormatPattern
|
||||
(uploadCount +"/" + levelInfo.getMaxUploadCount() );
|
||||
}
|
||||
|
||||
/**
|
||||
* used to set the non revert image percentage
|
||||
* @param notRevertPercentage
|
||||
*/
|
||||
private void setImageRevertPercentage(int notRevertPercentage){
|
||||
imageRevertsProgressbar.setProgress(notRevertPercentage);
|
||||
String revertPercentage = Integer.toString(notRevertPercentage);
|
||||
imageRevertsProgressbar.setProgressTextFormatPattern(revertPercentage + "%%");
|
||||
imagesRevertLimitText.setText(getResources().getString(R.string.achievements_revert_limit_message)+ levelInfo.getMinNonRevertPercentage() + "%");
|
||||
}
|
||||
|
||||
/**
|
||||
* used to parse the JSONObject containing results
|
||||
* @param object
|
||||
*/
|
||||
private void parseJson(JSONObject object) {
|
||||
try {
|
||||
achievements.setUniqueUsedImages(object.getInt("uniqueUsedImages"));
|
||||
achievements.setArticlesUsingImages(object.getInt("articlesUsingImages"));
|
||||
achievements.setThanksReceived(object.getInt("thanksReceived"));
|
||||
achievements.setImagesEditedBySomeoneElse(object.getInt("imagesEditedBySomeoneElse"));
|
||||
JSONObject featuredImages = object.getJSONObject("featuredImages");
|
||||
achievements.setFeaturedImages
|
||||
(featuredImages.getInt("Quality_images") +
|
||||
featuredImages.getInt("Featured_pictures_on_Wikimedia_Commons"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
isStatisticsFetched = true;
|
||||
hideProgressBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used the inflate the fetched statistics of the images uploaded by user
|
||||
* and assign badge and level
|
||||
* @param achievements
|
||||
*/
|
||||
private void inflateAchievements(Achievements achievements ){
|
||||
thanksReceived.setText(Integer.toString(achievements.getThanksReceived()));
|
||||
imagesUsedByWikiProgessbar.setProgress
|
||||
(100*achievements.getUniqueUsedImages()/levelInfo.getMaxUniqueImages() );
|
||||
imagesUsedByWikiProgessbar.setProgressTextFormatPattern
|
||||
(achievements.getUniqueUsedImages() + "/" + levelInfo.getMaxUniqueImages());
|
||||
imagesFeatured.setText(Integer.toString(achievements.getFeaturedImages()));
|
||||
String levelUpInfoString = getString(R.string.level);
|
||||
levelUpInfoString += " " + Integer.toString(levelInfo.getLevelNumber());
|
||||
levelNumber.setText(levelUpInfoString);
|
||||
final ContextThemeWrapper wrapper = new ContextThemeWrapper(this, levelInfo.getLevelStyle());
|
||||
Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.badge, wrapper.getTheme());
|
||||
Bitmap bitmap = BitmapUtils.drawableToBitmap(drawable);
|
||||
BitmapDrawable bitmapImage = BitmapUtils.writeOnDrawable(bitmap, Integer.toString(levelInfo.getLevelNumber()),this);
|
||||
imageView.setImageDrawable(bitmapImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a way to change current activity to AchievementActivity
|
||||
* @param context
|
||||
*/
|
||||
public static void startYourself(Context context) {
|
||||
Intent intent = new Intent(context, AchievementsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* to hide progressbar
|
||||
*/
|
||||
private void hideProgressBar() {
|
||||
if (progressBar != null && isUploadFetched && isStatisticsFetched && isRevertFetched) {
|
||||
levelInfo = LevelController.LevelInfo.from(achievements.getImagesUploaded(),
|
||||
achievements.getUniqueUsedImages(),
|
||||
achievements.getNotRevertPercentage());
|
||||
inflateAchievements(achievements);
|
||||
setUploadProgress(achievements.getImagesUploaded());
|
||||
setImageRevertPercentage(achievements.getNotRevertPercentage());
|
||||
progressBar.setVisibility(View.GONE);
|
||||
layoutImageReverts.setVisibility(View.VISIBLE);
|
||||
layoutImageUploaded.setVisibility(View.VISIBLE);
|
||||
layoutImageUsedByWiki.setVisibility(View.VISIBLE);
|
||||
layoutStatistics.setVisibility(View.VISIBLE);
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
levelNumber.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* used to hide the layouts while fetching results from api
|
||||
*/
|
||||
private void hideLayouts(){
|
||||
layoutImageUsedByWiki.setVisibility(View.INVISIBLE);
|
||||
layoutImageUploaded.setVisibility(View.INVISIBLE);
|
||||
layoutImageReverts.setVisibility(View.INVISIBLE);
|
||||
layoutStatistics.setVisibility(View.INVISIBLE);
|
||||
imageView.setVisibility(View.INVISIBLE);
|
||||
levelNumber.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* It display the alertDialog with Image of screenshot
|
||||
* @param screenshot
|
||||
*/
|
||||
public void showAlert(Bitmap screenshot){
|
||||
AlertDialog.Builder alertadd = new AlertDialog.Builder(AchievementsActivity.this);
|
||||
LayoutInflater factory = LayoutInflater.from(AchievementsActivity.this);
|
||||
final View view = factory.inflate(R.layout.image_alert_layout, null);
|
||||
ImageView screenShotImage = (ImageView) view.findViewById(R.id.alert_image);
|
||||
screenShotImage.setImageBitmap(screenshot);
|
||||
TextView shareMessage = (TextView) view.findViewById(R.id.alert_text);
|
||||
shareMessage.setText(R.string.achievements_share_message);
|
||||
alertadd.setView(view);
|
||||
alertadd.setPositiveButton("Proceed", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
shareScreen(screenshot);
|
||||
}
|
||||
});
|
||||
alertadd.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
alertadd.show();
|
||||
}
|
||||
|
||||
@OnClick(R.id.images_upload_info)
|
||||
public void showUploadInfo(){
|
||||
launchAlert(getResources().getString(R.string.images_uploaded)
|
||||
,getResources().getString(R.string.images_uploaded_explanation));
|
||||
}
|
||||
|
||||
@OnClick(R.id.images_reverted_info)
|
||||
public void showRevertedInfo(){
|
||||
launchAlert(getResources().getString(R.string.image_reverts)
|
||||
,getResources().getString(R.string.images_reverted_explanation));
|
||||
}
|
||||
|
||||
@OnClick(R.id.images_used_by_wiki_info)
|
||||
public void showUsedByWikiInfo(){
|
||||
launchAlert(getResources().getString(R.string.images_used_by_wiki)
|
||||
,getResources().getString(R.string.images_used_explanation));
|
||||
}
|
||||
|
||||
/**
|
||||
* takes title and message as input to display alerts
|
||||
* @param title
|
||||
* @param message
|
||||
*/
|
||||
private void launchAlert(String title, String message){
|
||||
new AlertDialog.Builder(AchievementsActivity.this)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setCancelable(true)
|
||||
.setNeutralButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(this, getResources().getString(R.string.user_not_logged_in));
|
||||
sessionManager.forceLogin(this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package fr.free.nrw.commons.achievements;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
public class BitmapUtils {
|
||||
|
||||
/**
|
||||
* write level Number on the badge
|
||||
* @param bm
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
public static BitmapDrawable writeOnDrawable(Bitmap bm, String text, Context context){
|
||||
Bitmap.Config config = bm.getConfig();
|
||||
if(config == null){
|
||||
config = Bitmap.Config.ARGB_8888;
|
||||
}
|
||||
Bitmap bitmap = Bitmap.createBitmap(bm.getWidth(),bm.getHeight(),config);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.drawBitmap(bm, 0, 0, null);
|
||||
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
paint.setColor(Color.WHITE);
|
||||
paint.setTextSize(Math.round(canvas.getHeight()/2));
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
Rect rectText = new Rect();
|
||||
paint.getTextBounds(text,0, text.length(),rectText);
|
||||
canvas.drawText(text, Math.round(canvas.getWidth()/2),Math.round(canvas.getHeight()/1.35), paint);
|
||||
return new BitmapDrawable(context.getResources(), bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Drawable to bitmap
|
||||
* @param drawable
|
||||
* @return
|
||||
*/
|
||||
public static Bitmap drawableToBitmap (Drawable drawable) {
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
return ((BitmapDrawable)drawable).getBitmap();
|
||||
}
|
||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package fr.free.nrw.commons.achievements;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
|
||||
/**
|
||||
* calculates the level of the user
|
||||
*/
|
||||
public class LevelController {
|
||||
|
||||
public LevelInfo level;
|
||||
public enum LevelInfo{
|
||||
LEVEL_1(1, R.style.LevelOne, 5, 20, 85),
|
||||
LEVEL_2(2, R.style.LevelTwo, 10, 30, 86),
|
||||
LEVEL_3(3, R.style.LevelThree, 15,40, 87),
|
||||
LEVEL_4(4, R.style.LevelFour,20,50, 88),
|
||||
LEVEL_5(5, R.style.LevelFive, 25, 60, 89),
|
||||
LEVEL_6(6,R.style.LevelOne,30,70, 90),
|
||||
LEVEL_7(7, R.style.LevelTwo, 40, 80, 90),
|
||||
LEVEL_8(8, R.style.LevelThree, 45, 90, 90),
|
||||
LEVEL_9(9, R.style.LevelFour, 50, 100, 90),
|
||||
LEVEL_10(10, R.style.LevelFive, 55, 110, 90),
|
||||
LEVEL_11(11,R.style.LevelOne, 60, 120, 90),
|
||||
LEVEL_12(12,R.style.LevelTwo,65 , 130, 90),
|
||||
LEVEL_13(13,R.style.LevelThree, 70, 140, 90),
|
||||
LEVEL_14(14,R.style.LevelFour, 75 , 150, 90),
|
||||
LEVEL_15(15,R.style.LevelFive, 80, 160, 90);
|
||||
|
||||
private int levelNumber;
|
||||
private int levelStyle;
|
||||
private int maxUniqueImages;
|
||||
private int maxUploadCount;
|
||||
private int minNonRevertPercentage;
|
||||
|
||||
LevelInfo(int levelNumber,
|
||||
int levelStyle,
|
||||
int maxUniqueImages,
|
||||
int maxUploadCount,
|
||||
int minNonRevertPercentage) {
|
||||
this.levelNumber = levelNumber;
|
||||
this.levelStyle = levelStyle;
|
||||
this.maxUniqueImages = maxUniqueImages;
|
||||
this.maxUploadCount = maxUploadCount;
|
||||
this.minNonRevertPercentage = minNonRevertPercentage;
|
||||
}
|
||||
|
||||
public static LevelInfo from(int imagesUploaded,
|
||||
int uniqueImagesUsed,
|
||||
int nonRevertRate) {
|
||||
LevelInfo level = LEVEL_15;
|
||||
|
||||
for (LevelInfo levelInfo : LevelInfo.values()) {
|
||||
if (imagesUploaded < levelInfo.maxUploadCount
|
||||
|| uniqueImagesUsed < levelInfo.maxUniqueImages
|
||||
|| nonRevertRate < levelInfo.minNonRevertPercentage ) {
|
||||
level = levelInfo;
|
||||
return level;
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
public int getLevelStyle() {
|
||||
return levelStyle;
|
||||
}
|
||||
|
||||
public int getLevelNumber() {
|
||||
return levelNumber;
|
||||
}
|
||||
|
||||
public int getMaxUniqueImages() {
|
||||
return maxUniqueImages;
|
||||
}
|
||||
|
||||
public int getMaxUploadCount() {
|
||||
return maxUploadCount;
|
||||
}
|
||||
|
||||
public int getMinNonRevertPercentage(){
|
||||
return minNonRevertPercentage;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -135,11 +135,6 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
}
|
||||
}
|
||||
|
||||
public static void startYourself(Context context) {
|
||||
Intent intent = new Intent(context, LoginActivity.class);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
private void forgotPassword() {
|
||||
Utils.handleWebUrl(this, Uri.parse(BuildConfig.FORGOT_PASSWORD_URL));
|
||||
}
|
||||
|
|
@ -445,4 +440,9 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
loginButton.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
public static void startYourself(Context context) {
|
||||
Intent intent = new Intent(context, LoginActivity.class);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@ import dagger.Module;
|
|||
import dagger.android.ContributesAndroidInjector;
|
||||
import fr.free.nrw.commons.AboutActivity;
|
||||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.achievements.AchievementsActivity;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.auth.SignupActivity;
|
||||
import fr.free.nrw.commons.category.CategoryDetailsActivity;
|
||||
import fr.free.nrw.commons.contributions.ContributionsActivity;
|
||||
import fr.free.nrw.commons.category.CategoryImagesActivity;
|
||||
import fr.free.nrw.commons.explore.SearchActivity;
|
||||
|
||||
import fr.free.nrw.commons.nearby.NearbyActivity;
|
||||
import fr.free.nrw.commons.notification.NotificationActivity;
|
||||
import fr.free.nrw.commons.settings.SettingsActivity;
|
||||
|
|
@ -58,4 +60,8 @@ public abstract class ActivityBuilderModule {
|
|||
|
||||
@ContributesAndroidInjector
|
||||
abstract CategoryDetailsActivity bindCategoryDetailsActivity();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract AchievementsActivity bindAchievementsActivity();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
|||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.apache.http.params.CoreProtocolPNames;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.mediawiki.api.ApiResult;
|
||||
import org.mediawiki.api.MWApi;
|
||||
import org.w3c.dom.Element;
|
||||
|
|
@ -53,6 +54,10 @@ import fr.free.nrw.commons.notification.NotificationUtils;
|
|||
import in.yuvi.http.fluent.Http;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static fr.free.nrw.commons.utils.ContinueUtils.getQueryContinue;
|
||||
|
|
@ -902,13 +907,11 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
|||
.param("meta", "userinfo")
|
||||
.param("uiprop", "blockinfo")
|
||||
.get();
|
||||
if(result != null) {
|
||||
if (result != null) {
|
||||
String blockEnd = result.getString("/api/query/userinfo/@blockexpiry");
|
||||
if(blockEnd.equals("infinite"))
|
||||
{
|
||||
if (blockEnd.equals("infinite")) {
|
||||
userBlocked = true;
|
||||
}
|
||||
else if (!blockEnd.isEmpty()) {
|
||||
} else if (!blockEnd.isEmpty()) {
|
||||
Date endDate = parseMWDate(blockEnd);
|
||||
Date current = new Date();
|
||||
userBlocked = endDate.after(current);
|
||||
|
|
@ -922,6 +925,68 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
|
|||
return userBlocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* This takes userName as input, which is then used to fetch the feedback/achievements
|
||||
* statistics using OkHttp and JavaRx. This function return JSONObject
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public Single<JSONObject> getAchievements(String userName) {
|
||||
final String fetchAchievementUrlTemplate =
|
||||
wikiMediaToolforgeUrl + "urbanecmbot/commonsmisc/feedback.py";
|
||||
return Single.fromCallable(() -> {
|
||||
String url = String.format(
|
||||
Locale.ENGLISH,
|
||||
fetchAchievementUrlTemplate,
|
||||
new PageTitle(userName).getText());
|
||||
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
|
||||
urlBuilder.addQueryParameter("user", userName);
|
||||
Log.i("url", urlBuilder.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(urlBuilder.toString())
|
||||
.build();
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Response response = client.newCall(request).execute();
|
||||
String jsonData = response.body().string();
|
||||
JSONObject jsonObject = new JSONObject(jsonData);
|
||||
return jsonObject;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This takes userName as input, which is then used to fetch the no of images deleted
|
||||
* using OkHttp and JavaRx. This function return JSONObject
|
||||
* @param userName
|
||||
* @return
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public Single<JSONObject> getRevertCount(String userName){
|
||||
final String fetchRevertCountUrlTemplate =
|
||||
wikiMediaToolforgeUrl + "urbanecmbot/commonsmisc/feedback.py";
|
||||
return Single.fromCallable(() -> {
|
||||
String url = String.format(
|
||||
Locale.ENGLISH,
|
||||
fetchRevertCountUrlTemplate,
|
||||
new PageTitle(userName).getText());
|
||||
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
|
||||
urlBuilder.addQueryParameter("user", userName);
|
||||
urlBuilder.addQueryParameter("fetch","deletedUploads");
|
||||
Log.i("url", urlBuilder.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(urlBuilder.toString())
|
||||
.build();
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Response response = client.newCall(request).execute();
|
||||
String jsonData = response.body().string();
|
||||
JSONObject jsonRevertObject = new JSONObject(jsonData);
|
||||
return jsonRevertObject;
|
||||
});
|
||||
}
|
||||
|
||||
private Date parseMWDate(String mwDate) {
|
||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); // Assuming MW always gives me UTC
|
||||
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package fr.free.nrw.commons.mwapi;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
|
@ -97,6 +99,12 @@ public interface MediaWikiApi {
|
|||
|
||||
boolean isUserBlockedFromCommons();
|
||||
|
||||
@NonNull
|
||||
Single<JSONObject> getAchievements(String userName);
|
||||
|
||||
@NonNull
|
||||
Single<JSONObject> getRevertCount(String userName);
|
||||
|
||||
interface ProgressListener {
|
||||
void onProgress(long transferred, long total);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import android.support.v7.widget.Toolbar;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
|
@ -24,6 +25,7 @@ import fr.free.nrw.commons.BuildConfig;
|
|||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.achievements.AchievementsActivity;
|
||||
import fr.free.nrw.commons.auth.AccountUtil;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.contributions.ContributionsActivity;
|
||||
|
|
@ -68,12 +70,19 @@ public abstract class NavigationBaseActivity extends BaseActivity
|
|||
|
||||
View navHeaderView = navigationView.getHeaderView(0);
|
||||
TextView username = navHeaderView.findViewById(R.id.username);
|
||||
|
||||
AccountManager accountManager = AccountManager.get(this);
|
||||
Account[] allAccounts = accountManager.getAccountsByType(AccountUtil.ACCOUNT_TYPE);
|
||||
if (allAccounts.length != 0) {
|
||||
username.setText(allAccounts[0].name);
|
||||
}
|
||||
ImageView userIcon = navHeaderView.findViewById(R.id.user_icon);
|
||||
userIcon.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
drawerLayout.closeDrawer(navigationView);
|
||||
AchievementsActivity.startYourself(NavigationBaseActivity.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void initBackButton() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue