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
This commit is contained in:
Tanvi Dadu 2018-07-04 20:26:26 +05:30 committed by Josephine Lim
parent bd1555f558
commit 12fb75a8bb
10 changed files with 353 additions and 67 deletions

View file

@ -1,7 +1,9 @@
package fr.free.nrw.commons.achievements; package fr.free.nrw.commons.achievements;
import android.util.Log;
/** /**
* represnts Achievements * represnts Achievements class ans stores all the parameters
*/ */
public class Achievements { public class Achievements {
private int uniqueUsedImages; private int uniqueUsedImages;
@ -10,24 +12,41 @@ public class Achievements {
private int imagesEditedBySomeoneElse; private int imagesEditedBySomeoneElse;
private int featuredImages; private int featuredImages;
private int imagesUploaded; private int imagesUploaded;
private int revertCount;
public Achievements(){ 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, public Achievements(int uniqueUsedImages,
int articlesUsingImages, int articlesUsingImages,
int thanksReceived, int thanksReceived,
int imagesEditedBySomeoneElse, int imagesEditedBySomeoneElse,
int featuredImages, int featuredImages,
int imagesUploaded) { int imagesUploaded,
int revertCount) {
this.uniqueUsedImages = uniqueUsedImages; this.uniqueUsedImages = uniqueUsedImages;
this.articlesUsingImages = articlesUsingImages; this.articlesUsingImages = articlesUsingImages;
this.thanksReceived = thanksReceived; this.thanksReceived = thanksReceived;
this.imagesEditedBySomeoneElse = imagesEditedBySomeoneElse; this.imagesEditedBySomeoneElse = imagesEditedBySomeoneElse;
this.featuredImages = featuredImages; this.featuredImages = featuredImages;
this.imagesUploaded = imagesUploaded; this.imagesUploaded = imagesUploaded;
this.revertCount = revertCount;
} }
/**
* Builder class for Achievements class
*/
public class AchievementsBuilder { public class AchievementsBuilder {
private int nestedUniqueUsedImages; private int nestedUniqueUsedImages;
private int nestedArticlesUsingImages; private int nestedArticlesUsingImages;
@ -35,6 +54,7 @@ public class Achievements {
private int nestedImagesEditedBySomeoneElse; private int nestedImagesEditedBySomeoneElse;
private int nestedFeaturedImages; private int nestedFeaturedImages;
private int nestedImagesUploaded; private int nestedImagesUploaded;
private int nestedRevertCount;
public AchievementsBuilder setUniqueUsedImages(int uniqueUsedImages) { public AchievementsBuilder setUniqueUsedImages(int uniqueUsedImages) {
this.nestedUniqueUsedImages = uniqueUsedImages; this.nestedUniqueUsedImages = uniqueUsedImages;
@ -66,62 +86,120 @@ public class Achievements {
return this; return this;
} }
public AchievementsBuilder setRevertCount( int revertCount){
this.nestedRevertCount = revertCount;
return this;
}
public Achievements createAchievements(){ public Achievements createAchievements(){
return new Achievements(nestedUniqueUsedImages, return new Achievements(nestedUniqueUsedImages,
nestedArticlesUsingImages, nestedArticlesUsingImages,
nestedThanksReceived, nestedThanksReceived,
nestedImagesEditedBySomeoneElse, nestedImagesEditedBySomeoneElse,
nestedFeaturedImages, nestedFeaturedImages,
nestedImagesUploaded); nestedImagesUploaded,
nestedRevertCount);
} }
} }
/**
* getter function to get count of images uploaded
* @return
*/
public int getImagesUploaded() { public int getImagesUploaded() {
return imagesUploaded; return imagesUploaded;
} }
/**
* getter function to get count of featured images
* @return
*/
public int getFeaturedImages() { public int getFeaturedImages() {
return featuredImages; return featuredImages;
} }
public int getImagesEditedBySomeoneElse() { /**
return imagesEditedBySomeoneElse; * getter function to get count of thanks received
} * @return
*/
public int getThanksReceived() { public int getThanksReceived() {
return thanksReceived; return thanksReceived;
} }
public int getArticlesUsingImages() { /**
return articlesUsingImages; * getter function to get count of unique images used by wiki
} * @return
*/
public int getUniqueUsedImages() { public int getUniqueUsedImages() {
return uniqueUsedImages; return uniqueUsedImages;
} }
/**
* setter function to count of images uploaded
* @param imagesUploaded
*/
public void setImagesUploaded(int imagesUploaded) { public void setImagesUploaded(int imagesUploaded) {
this.imagesUploaded = imagesUploaded; this.imagesUploaded = imagesUploaded;
} }
/**
* setter function to set count of featured images
* @param featuredImages
*/
public void setFeaturedImages(int featuredImages) { public void setFeaturedImages(int featuredImages) {
this.featuredImages = featuredImages; this.featuredImages = featuredImages;
} }
/**
* setter function to set the count of images edited by someone
* @param imagesEditedBySomeoneElse
*/
public void setImagesEditedBySomeoneElse(int imagesEditedBySomeoneElse) { public void setImagesEditedBySomeoneElse(int imagesEditedBySomeoneElse) {
this.imagesEditedBySomeoneElse = imagesEditedBySomeoneElse; this.imagesEditedBySomeoneElse = imagesEditedBySomeoneElse;
} }
/**
* setter function to set count of thanks received
* @param thanksReceived
*/
public void setThanksReceived(int thanksReceived) { public void setThanksReceived(int thanksReceived) {
this.thanksReceived = thanksReceived; this.thanksReceived = thanksReceived;
} }
/**
* setter function to count of articles using images uploaded
* @param articlesUsingImages
*/
public void setArticlesUsingImages(int articlesUsingImages) { public void setArticlesUsingImages(int articlesUsingImages) {
this.articlesUsingImages = articlesUsingImages; this.articlesUsingImages = articlesUsingImages;
} }
/**
* setter function to set count of uniques images used by wiki
* @param uniqueUsedImages
*/
public void setUniqueUsedImages(int uniqueUsedImages) { public void setUniqueUsedImages(int uniqueUsedImages) {
this.uniqueUsedImages = 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;
}
}
} }

View file

@ -1,6 +1,8 @@
package fr.free.nrw.commons.achievements; package fr.free.nrw.commons.achievements;
import android.accounts.Account;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@ -38,6 +40,7 @@ import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Optional;
import javax.inject.Inject; import javax.inject.Inject;
@ -49,6 +52,7 @@ import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.theme.NavigationBaseActivity;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
@ -63,8 +67,8 @@ public class AchievementsActivity extends NavigationBaseActivity {
private static final double BADGE_IMAGE_HEIGHT_RATIO = 0.3; private static final double BADGE_IMAGE_HEIGHT_RATIO = 0.3;
private Boolean isUploadFetched = false; private Boolean isUploadFetched = false;
private Boolean isStatisticsFetched = false; private Boolean isStatisticsFetched = false;
private Boolean isRevertFetched = false;
private Achievements achievements = new Achievements(); private Achievements achievements = new Achievements();
private LevelController level;
private LevelController.LevelInfo levelInfo; private LevelController.LevelInfo levelInfo;
@BindView(R.id.achievement_badge) @BindView(R.id.achievement_badge)
@ -79,8 +83,12 @@ public class AchievementsActivity extends NavigationBaseActivity {
CircleProgressBar imagesUploadedProgressbar; CircleProgressBar imagesUploadedProgressbar;
@BindView(R.id.images_used_by_wiki_progressbar) @BindView(R.id.images_used_by_wiki_progressbar)
CircleProgressBar imagesUsedByWikiProgessbar; CircleProgressBar imagesUsedByWikiProgessbar;
@BindView(R.id.image_reverts_progressbar)
CircleProgressBar imageRevertsProgressbar;
@BindView(R.id.image_featured) @BindView(R.id.image_featured)
TextView imagesFeatured; TextView imagesFeatured;
@BindView(R.id.images_revert_limit_text)
TextView imagesRevertLimitText;
@BindView(R.id.progressBar) @BindView(R.id.progressBar)
ProgressBar progressBar; ProgressBar progressBar;
@BindView(R.id.layout_image_uploaded) @BindView(R.id.layout_image_uploaded)
@ -133,6 +141,7 @@ public class AchievementsActivity extends NavigationBaseActivity {
hideLayouts(); hideLayouts();
setAchievements(); setAchievements();
setUploadCount(); setUploadCount();
setRevertCount();
initDrawer(); initDrawer();
} }
@ -141,14 +150,8 @@ public class AchievementsActivity extends NavigationBaseActivity {
*/ */
@OnClick(R.id.achievement_info) @OnClick(R.id.achievement_info)
public void showInfoDialog(){ public void showInfoDialog(){
new AlertDialog.Builder(AchievementsActivity.this) launchAlert(getResources().getString(R.string.Achievements)
.setTitle(R.string.Achievements) ,getResources().getString(R.string.achievements_info_message));
.setMessage(R.string.achievements_info_message)
.setCancelable(true)
.setNeutralButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
.create()
.show();
} }
@Override @Override
@ -198,27 +201,72 @@ public class AchievementsActivity extends NavigationBaseActivity {
* which then calls parseJson when results are fetched * which then calls parseJson when results are fetched
*/ */
private void setAchievements() { private void setAchievements() {
if(checkAccount()) {
compositeDisposable.add(mediaWikiApi compositeDisposable.add(mediaWikiApi
.getAchievements(sessionManager.getCurrentAccount().name) .getAchievements(sessionManager.getCurrentAccount().name)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
jsonObject -> parseJson(jsonObject) 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 * used to the count of images uploaded by user
*/ */
private void setUploadCount() { private void setUploadCount() {
if(checkAccount()) {
compositeDisposable.add(mediaWikiApi compositeDisposable.add(mediaWikiApi
.getUploadCount(sessionManager.getCurrentAccount().name) .getUploadCount(sessionManager.getCurrentAccount().name)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
uploadCount -> achievements.setImagesUploaded(uploadCount), uploadCount -> setAchievementsUploadCount(uploadCount),
t -> Timber.e(t, "Fetching upload count failed") 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; isUploadFetched = true;
hideProgressBar(); hideProgressBar();
} }
@ -228,16 +276,25 @@ public class AchievementsActivity extends NavigationBaseActivity {
* @param uploadCount * @param uploadCount
*/ */
private void setUploadProgress(int uploadCount){ private void setUploadProgress(int uploadCount){
imagesUploadedProgressbar.setProgress imagesUploadedProgressbar.setProgress
(100*uploadCount/levelInfo.getMaxUploadCount()); (100*uploadCount/levelInfo.getMaxUploadCount());
imagesUploadedProgressbar.setProgressTextFormatPattern imagesUploadedProgressbar.setProgressTextFormatPattern
(uploadCount +"/" + levelInfo.getMaxUploadCount() ); (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 * used to parse the JSONObject containing results
*
* @param object * @param object
*/ */
private void parseJson(JSONObject object) { private void parseJson(JSONObject object) {
@ -281,7 +338,6 @@ public class AchievementsActivity extends NavigationBaseActivity {
/** /**
* Creates a way to change current activity to AchievementActivity * Creates a way to change current activity to AchievementActivity
*
* @param context * @param context
*/ */
public static void startYourself(Context context) { public static void startYourself(Context context) {
@ -295,10 +351,13 @@ public class AchievementsActivity extends NavigationBaseActivity {
* to hide progressbar * to hide progressbar
*/ */
private void hideProgressBar() { private void hideProgressBar() {
if (progressBar != null && isUploadFetched && isStatisticsFetched) { if (progressBar != null && isUploadFetched && isStatisticsFetched && isRevertFetched) {
levelInfo = LevelController.LevelInfo.from(achievements.getImagesUploaded(),achievements.getUniqueUsedImages()); levelInfo = LevelController.LevelInfo.from(achievements.getImagesUploaded(),
achievements.getUniqueUsedImages(),
achievements.getNotRevertPercentage());
inflateAchievements(achievements); inflateAchievements(achievements);
setUploadProgress(achievements.getImagesUploaded()); setUploadProgress(achievements.getImagesUploaded());
setImageRevertPercentage(achievements.getNotRevertPercentage());
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
layoutImageReverts.setVisibility(View.VISIBLE); layoutImageReverts.setVisibility(View.VISIBLE);
layoutImageUploaded.setVisibility(View.VISIBLE); layoutImageUploaded.setVisibility(View.VISIBLE);
@ -348,4 +407,52 @@ public class AchievementsActivity extends NavigationBaseActivity {
alertadd.show(); 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;
}
} }

View file

@ -1,5 +1,7 @@
package fr.free.nrw.commons.achievements; package fr.free.nrw.commons.achievements;
import android.util.Log;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
/** /**
@ -9,39 +11,49 @@ public class LevelController {
public LevelInfo level; public LevelInfo level;
public enum LevelInfo{ public enum LevelInfo{
LEVEL_15(15,R.style.LevelFive, 80, 160), LEVEL_1(1, R.style.LevelOne, 5, 20, 85),
LEVEL_14(14,R.style.LevelFour, 75 , 150), LEVEL_2(2, R.style.LevelTwo, 10, 30, 86),
LEVEL_13(13,R.style.LevelThree, 70, 140), LEVEL_3(3, R.style.LevelThree, 15,40, 87),
LEVEL_12(12,R.style.LevelTwo,65 , 130), LEVEL_4(4, R.style.LevelFour,20,50, 88),
LEVEL_11(11,R.style.LevelOne, 60, 120), LEVEL_5(5, R.style.LevelFive, 25, 60, 89),
LEVEL_10(10, R.style.LevelFive, 55, 110), LEVEL_6(6,R.style.LevelOne,30,70, 90),
LEVEL_9(9, R.style.LevelFour, 50, 100), LEVEL_7(7, R.style.LevelTwo, 40, 80, 90),
LEVEL_8(8, R.style.LevelThree, 45, 90), LEVEL_8(8, R.style.LevelThree, 45, 90, 90),
LEVEL_7(7, R.style.LevelTwo, 40, 80), LEVEL_9(9, R.style.LevelFour, 50, 100, 90),
LEVEL_6(6,R.style.LevelOne,30,70), LEVEL_10(10, R.style.LevelFive, 55, 110, 90),
LEVEL_5(5, R.style.LevelFive, 25, 60), LEVEL_11(11,R.style.LevelOne, 60, 120, 90),
LEVEL_4(4, R.style.LevelFour,20,50), LEVEL_12(12,R.style.LevelTwo,65 , 130, 90),
LEVEL_3(3, R.style.LevelThree, 15,40), LEVEL_13(13,R.style.LevelThree, 70, 140, 90),
LEVEL_2(2, R.style.LevelTwo, 10, 30), LEVEL_14(14,R.style.LevelFour, 75 , 150, 90),
LEVEL_1(1, R.style.LevelOne, 5, 20 ); LEVEL_15(15,R.style.LevelFive, 80, 160, 90);
private int levelNumber; private int levelNumber;
private int levelStyle; private int levelStyle;
private int maxUniqueImages; private int maxUniqueImages;
private int maxUploadCount; private int maxUploadCount;
private int minNonRevertPercentage;
LevelInfo(int levelNumber, int levelStyle, int maxUniqueImages, int maxUploadCount) { LevelInfo(int levelNumber,
int levelStyle,
int maxUniqueImages,
int maxUploadCount,
int minNonRevertPercentage) {
this.levelNumber = levelNumber; this.levelNumber = levelNumber;
this.levelStyle = levelStyle; this.levelStyle = levelStyle;
this.maxUniqueImages = maxUniqueImages; this.maxUniqueImages = maxUniqueImages;
this.maxUploadCount = maxUploadCount; this.maxUploadCount = maxUploadCount;
this.minNonRevertPercentage = minNonRevertPercentage;
} }
public static LevelInfo from(int imagesUploaded, int uniqueImagesUsed) { public static LevelInfo from(int imagesUploaded,
LevelInfo level = LEVEL_1; int uniqueImagesUsed,
int nonRevertRate) {
LevelInfo level = LEVEL_15;
for (LevelInfo levelInfo : LevelInfo.values()) { for (LevelInfo levelInfo : LevelInfo.values()) {
if (imagesUploaded > levelInfo.maxUploadCount && uniqueImagesUsed > levelInfo.maxUniqueImages) { if (imagesUploaded < levelInfo.maxUploadCount
|| uniqueImagesUsed < levelInfo.maxUniqueImages
|| nonRevertRate < levelInfo.minNonRevertPercentage ) {
level = levelInfo; level = levelInfo;
return level; return level;
} }
@ -57,10 +69,6 @@ public class LevelController {
return levelNumber; return levelNumber;
} }
public void setLevelStyle(int levelStyle) {
this.levelStyle = levelStyle;
}
public int getMaxUniqueImages() { public int getMaxUniqueImages() {
return maxUniqueImages; return maxUniqueImages;
} }
@ -68,6 +76,10 @@ public class LevelController {
public int getMaxUploadCount() { public int getMaxUploadCount() {
return maxUploadCount; return maxUploadCount;
} }
public int getMinNonRevertPercentage(){
return minNonRevertPercentage;
}
} }
} }

View file

@ -6,6 +6,7 @@ import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
@ -440,4 +441,9 @@ public class LoginActivity extends AccountAuthenticatorActivity {
loginButton.setEnabled(enabled); loginButton.setEnabled(enabled);
} }
} }
public static void startYourself(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
}
} }

View file

@ -88,4 +88,10 @@ public class SessionManager {
.map(a -> accountManager.removeAccount(a, null, null).getResult())) .map(a -> accountManager.removeAccount(a, null, null).getResult()))
.doOnComplete(() -> currentAccount = null); .doOnComplete(() -> currentAccount = null);
} }
public void forceLogin(Context context) {
if (context != null) {
LoginActivity.startYourself(context);
}
}
} }

View file

@ -651,6 +651,37 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
} }
/**
* 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) { 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 SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); // Assuming MW always gives me UTC
try { try {

View file

@ -80,6 +80,9 @@ public interface MediaWikiApi {
@NonNull @NonNull
Single<JSONObject> getAchievements(String userName); Single<JSONObject> getAchievements(String userName);
@NonNull
Single<JSONObject> getRevertCount(String userName);
interface ProgressListener { interface ProgressListener {
void onProgress(long transferred, long total); void onProgress(long transferred, long total);
} }

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#00376d"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
</vector>

View file

@ -71,9 +71,20 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/activity_margin_horizontal" android:layout_marginLeft="@dimen/activity_margin_horizontal"
android:layout_marginStart="@dimen/activity_margin_horizontal" android:layout_marginStart="@dimen/activity_margin_horizontal"
android:id="@+id/images_upload_text_param"
android:layout_marginTop="@dimen/achievements_activity_margin_vertical" android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
android:text="@string/images_uploaded" /> android:text="@string/images_uploaded" />
<ImageView
android:layout_width="12dp"
android:layout_height="12dp"
android:id="@+id/images_upload_info"
android:layout_marginTop="8dp"
android:layout_marginRight="@dimen/activity_margin_horizontal"
android:layout_toRightOf="@+id/images_upload_text_param"
app:srcCompat="@drawable/ic_info_outline_blue_24dp"
android:layout_marginLeft="8dp" />
<com.dinuscxj.progressbar.CircleProgressBar <com.dinuscxj.progressbar.CircleProgressBar
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
@ -111,11 +122,22 @@
android:layout_marginStart="@dimen/activity_margin_horizontal" android:layout_marginStart="@dimen/activity_margin_horizontal"
android:text="@string/image_reverts" /> android:text="@string/image_reverts" />
<ImageView
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginTop="8dp"
android:layout_marginRight="@dimen/activity_margin_horizontal"
android:id="@+id/images_reverted_info"
android:layout_toRightOf="@+id/images_reverted_text"
app:srcCompat="@drawable/ic_info_outline_blue_24dp"
android:layout_marginLeft="8dp" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="(minimum required: 90%)" android:text="@string/achievements_revert_limit_message"
android:textSize="10dp" android:textSize="10dp"
android:id="@+id/images_revert_limit_text"
android:layout_marginLeft="@dimen/activity_margin_horizontal" android:layout_marginLeft="@dimen/activity_margin_horizontal"
android:layout_marginStart="@dimen/activity_margin_horizontal" android:layout_marginStart="@dimen/activity_margin_horizontal"
android:layout_below="@+id/images_reverted_text"/> android:layout_below="@+id/images_reverted_text"/>
@ -153,11 +175,22 @@
style="?android:textAppearanceMedium" style="?android:textAppearanceMedium"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/images_used_by_wiki_text"
android:layout_marginLeft="@dimen/activity_margin_horizontal" android:layout_marginLeft="@dimen/activity_margin_horizontal"
android:layout_marginStart="@dimen/activity_margin_horizontal" android:layout_marginStart="@dimen/activity_margin_horizontal"
android:layout_marginTop="@dimen/achievements_activity_margin_vertical" android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
android:text="@string/images_used_by_wiki" /> android:text="@string/images_used_by_wiki" />
<ImageView
android:layout_width="12dp"
android:layout_height="12dp"
android:id="@+id/images_used_by_wiki_info"
android:layout_marginTop="8dp"
android:layout_marginRight="@dimen/activity_margin_horizontal"
android:layout_toRightOf="@+id/images_used_by_wiki_text"
app:srcCompat="@drawable/ic_info_outline_blue_24dp"
android:layout_marginLeft="8dp" />
<com.dinuscxj.progressbar.CircleProgressBar <com.dinuscxj.progressbar.CircleProgressBar
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"

View file

@ -291,7 +291,12 @@
<string name="level">LEVEL</string> <string name="level">LEVEL</string>
<string name="images_uploaded">Images Uploaded</string> <string name="images_uploaded">Images Uploaded</string>
<string name="image_reverts">Images Not Reverted</string> <string name="image_reverts">Images Not Reverted</string>
<string name="images_used_by_wiki">Images Used By Wiki</string> <string name="images_used_by_wiki">Images Used</string>
<string name="achievements_share_message">Share your achievements with your friends!</string> <string name="achievements_share_message">Share your achievements with your friends!</string>
<string name="achievements_info_message">Your level increases as you meet these requirements. Items in the "statistics" section do not count towards your level.</string> <string name="achievements_info_message">Your level increases as you meet these requirements. Items in the "statistics" section do not count towards your level.</string>
<string name="achievements_revert_limit_message">minimum required: </string>
<string name="images_uploaded_explanation">The number of images you have uploaded to Commons, via any upload software</string>
<string name="images_reverted_explanation">The percentage of images you have uploaded to Commons that were not deleted</string>
<string name="images_used_explanation">The number of images you have uploaded to Commons that were used in Wikimedia articles</string>
<string name="user_not_logged_in">Login session expired, please log in again.</string>
</resources> </resources>