From 11c3772dd003287cd93ba0d35201e7b6cd759ff5 Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Fri, 17 Aug 2018 22:01:10 +0530 Subject: [PATCH 1/9] Add Traceur for getting meaningful RxJava stack traces (#1832) --- app/build.gradle | 1 + app/src/main/java/fr/free/nrw/commons/CommonsApplication.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index d6bdede1b0..1802eba338 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,6 +62,7 @@ dependencies { testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1' implementation 'com.dinuscxj:circleprogressbar:1.1.1' + implementation 'com.tspoon.traceur:traceur:1.0.1' implementation 'com.caverock:androidsvg:1.2.1' implementation 'com.github.bumptech.glide:glide:4.7.1' kapt 'com.github.bumptech.glide:compiler:4.7.1' diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index cb47f75e9a..2ceb22d06a 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -10,6 +10,8 @@ import com.facebook.stetho.Stetho; import com.squareup.leakcanary.LeakCanary; import com.squareup.leakcanary.RefWatcher; +import com.tspoon.traceur.Traceur; +import com.tspoon.traceur.TraceurConfig; import org.acra.ACRA; import org.acra.ReportingInteractionMode; @@ -69,6 +71,8 @@ public class CommonsApplication extends MultiDexApplication { @Override public void onCreate() { super.onCreate(); + Traceur.enableLogging(); + ApplicationlessInjection .getInstance(this) .getCommonsApplicationComponent() From 4c476e7a064102599daad0b59ce538de752ec77a Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 20 Aug 2018 11:32:45 +0300 Subject: [PATCH 2/9] Hotfix for overwrite issue in 2.8.0 (#1838) * This solution is an hotfix for overrite issue came back on 2.8.0 version. What I did is checking the extension, and if it is null, adding .jpg suffix. Because commons files always have suffixes, and we should compare file names after adding suffixes. Othervise overrides are possible. * Check if file title includes an extension already, by checking if is there any dot in it. * Fix logic error * Add uncovered tests * Remove unecessary line breaks * Make Javadocs more explicit --- app/src/main/java/fr/free/nrw/commons/Utils.java | 11 ++++++++++- .../fr/free/nrw/commons/UtilsFixExtensionTest.kt | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/Utils.java b/app/src/main/java/fr/free/nrw/commons/Utils.java index 4e4b46b01f..5f829abfce 100644 --- a/app/src/main/java/fr/free/nrw/commons/Utils.java +++ b/app/src/main/java/fr/free/nrw/commons/Utils.java @@ -111,7 +111,7 @@ public static int licenseNameFor(String license) { } /** - * Fixing incorrect extension + * Adds extension to filename. Converts to .jpg if system provides .jpeg, adds .jpg if no extension detected * @param title File name * @param extension Correct extension * @return File with correct extension @@ -128,6 +128,15 @@ public static String fixExtension(String title, String extension) { .endsWith("." + extension.toLowerCase(Locale.ENGLISH))) { title += "." + extension; } + + // If extension is still null, make it jpg. (Hotfix for https://github.com/commons-app/apps-android-commons/issues/228) + // If title has an extension in it, if won't be true + // FIXME: .png uploads fail when uploaded via Share + if (extension == null && title.lastIndexOf(".")<=0) { + extension = "jpg"; + title += "." + extension; + } + return title; } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/UtilsFixExtensionTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/UtilsFixExtensionTest.kt index 0082b9d284..1f3b127fdc 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/UtilsFixExtensionTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/UtilsFixExtensionTest.kt @@ -65,4 +65,14 @@ class UtilsFixExtensionTest { fun inWordJpegToJpgResultsInJpg() { assertEquals("X.jpeg.SAMPLE.jpg", fixExtension("X.jpeg.SAMPLE", "jpg")) } + + @Test + fun noExtensionShouldResultInJpg() { + assertEquals("Sample.jpg", fixExtension("Sample", null)) + } + + @Test + fun extensionAlreadyInTitleShouldRemain() { + assertEquals("Sample.jpg", fixExtension("Sample.jpg", null)) + } } From b743d021f079b02581b24f698d898317b034f43c Mon Sep 17 00:00:00 2001 From: Josephine Lim Date: Mon, 20 Aug 2018 20:07:29 +1000 Subject: [PATCH 3/9] Versioning and changelog for v2.8.2 (#1842) * Versioning for v2.8.2 * Changelog for v2.8.2 --- CHANGELOG.md | 3 +++ app/build.gradle | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60562d7519..b3ecfa8af5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Wikimedia Commons for Android +## v2.8.2 +- Fixed bug with uploads sent via Share being given .jpeg extensions and overwriting files of the same name + ## v2.8.1 - Fixed bug with category edits not being sent to server diff --git a/app/build.gradle b/app/build.gradle index 1802eba338..16dad0e6bd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -90,8 +90,8 @@ android { defaultConfig { applicationId 'fr.free.nrw.commons' - versionCode 88 - versionName '2.8.1' + versionCode 89 + versionName '2.8.2' setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) minSdkVersion project.minSdkVersion From b5849420fc24fbe5a2417e6610956f6aee3a2fad Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Mon, 3 Sep 2018 12:31:04 +0530 Subject: [PATCH 4/9] Add logs in wiki data edit and session refresh flow (#1874) --- .../mwapi/ApacheHttpClientMediaWikiApi.java | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java index 12b8972ffc..53050094b9 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java @@ -233,17 +233,27 @@ public String getEditToken() throws IOException { @Override public String getCentralAuthToken() throws IOException { - String centralAuthToken = api.action("centralauthtoken") - .get() - .getString("/api/centralauthtoken/@centralauthtoken"); + CustomApiResult result = api.action("centralauthtoken").get(); + String centralAuthToken = result.getString("/api/centralauthtoken/@centralauthtoken"); + Timber.d("MediaWiki Central auth token is %s", centralAuthToken); - if(centralAuthToken == null || centralAuthToken.isEmpty()) { + if ((centralAuthToken == null || centralAuthToken.isEmpty()) + && "notLoggedIn".equals(result.getString("api/error/@code"))) { + Timber.d("Central auth token isn't valid. Trying to fetch a fresh token"); api.removeAllCookies(); - String login = login(AccountUtil.getUserName(context), AccountUtil.getPassword(context)); - if(login.equals("PASS")) { + String loginResultCode = login(AccountUtil.getUserName(context), AccountUtil.getPassword(context)); + if(loginResultCode.equals("PASS")) { return getCentralAuthToken(); + } else if(loginResultCode.equals("2FA")) { + Timber.e("Cannot refresh session for 2FA enabled user. Login required"); + } else { + Timber.e("Error occurred in refreshing session. Error code is %s", loginResultCode); } + } else { + Timber.e("Error occurred while fetching auth token. Error code is %s and message is %s", + result.getString("api/error/@code"), + result.getString("api/error/@info")); } return centralAuthToken; } @@ -467,13 +477,12 @@ public boolean addWikidataEditTag(String revisionId) throws IOException { return false; } - Node node = result.getNode("api").getDocument(); - Element element = (Element) node; - - if (element != null && element.getAttribute("status").equals("success")) { + if ("success".equals(result.getString("api/tag/result/@status"))) { return true; } else { - Timber.e(result.getString("api/error/@code") + " " + result.getString("api/error/@info")); + Timber.e("Error occurred in creating claim. Error code is: %s and message is %s", + result.getString("api/error/@code"), + result.getString("api/error/@info")); } return false; } From 54caad265a5a028b24261ee2a7163114ce388212 Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Wed, 5 Sep 2018 13:55:09 +0530 Subject: [PATCH 5/9] Fix logout (#1875) --- .../java/fr/free/nrw/commons/CommonsApplication.java | 5 +++-- .../fr/free/nrw/commons/auth/SessionManager.java | 12 ++++++++++-- .../commons/mwapi/ApacheHttpClientMediaWikiApi.java | 11 +++++++++++ .../java/fr/free/nrw/commons/mwapi/CustomMwApi.java | 2 ++ .../java/fr/free/nrw/commons/mwapi/MediaWikiApi.java | 2 ++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index 2ceb22d06a..0e68af83c4 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -1,5 +1,6 @@ package fr.free.nrw.commons; +import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; @@ -128,6 +129,7 @@ public static RefWatcher getRefWatcher(Context context) { * @param context Application context * @param logoutListener Implementation of interface LogoutListener */ + @SuppressLint("CheckResult") public void clearApplicationData(Context context, LogoutListener logoutListener) { File cacheDirectory = context.getCacheDir(); File applicationDirectory = new File(cacheDirectory.getParent()); @@ -140,7 +142,7 @@ public void clearApplicationData(Context context, LogoutListener logoutListener) } } - sessionManager.clearAllAccounts() + sessionManager.logout() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(() -> { @@ -151,7 +153,6 @@ public void clearApplicationData(Context context, LogoutListener logoutListener) applicationPrefs.edit().putBoolean("firstrun", false).apply(); otherPrefs.edit().clear().apply(); updateAllDatabases(); - logoutListener.onLogoutComplete(); }); } diff --git a/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java b/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java index cd23d12829..e8745e25be 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java @@ -153,11 +153,19 @@ public void forceLogin(Context context) { } } - public Completable clearAllAccounts() { + /** + * 1. Clears existing accounts from account manager + * 2. Calls MediaWikiApi's logout function to clear cookies + * @return + */ + public Completable logout() { AccountManager accountManager = AccountManager.get(context); Account[] allAccounts = accountManager.getAccountsByType(BuildConfig.ACCOUNT_TYPE); return Completable.fromObservable(Observable.fromArray(allAccounts) .map(a -> accountManager.removeAccount(a, null, null).getResult())) - .doOnComplete(() -> currentAccount = null); + .doOnComplete(() -> { + mediaWikiApi.logout(); + currentAccount = null; + }); } } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java index 53050094b9..b9a0468d9a 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java @@ -1032,4 +1032,15 @@ private Date parseMWDate(String mwDate) { } } + /** + * Calls media wiki's logout API + */ + public void logout() { + try { + api.logout(); + } catch (IOException e) { + Timber.e(e, "Error occurred while logging out"); + } + } + } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/CustomMwApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/CustomMwApi.java index 1b9e93fa9c..21810d8656 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/CustomMwApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/CustomMwApi.java @@ -167,6 +167,8 @@ public void logout() throws IOException { // I should be doing more validation here, but meh isLoggedIn = false; this.action("logout").post(); + removeAllCookies(); + authCookie = null; } private CustomApiResult makeRequest(String method, HashMap params) throws IOException { diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java index d96e9b177a..687e898473 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java @@ -106,6 +106,8 @@ public interface MediaWikiApi { @NonNull Single getAchievements(String userName); + void logout(); + interface ProgressListener { void onProgress(long transferred, long total); } From 6eb01b8076400920a771bc24bcf54c22cb5f62c4 Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Thu, 6 Sep 2018 19:37:51 +0530 Subject: [PATCH 6/9] [WIP] Refactor feedback and quiz to reduce possibility of NPE (#1881) * Refactor feedback and quiz to reduce possibility of NPE * Handle throwables in quiz checker * Minor refactoring --- .../commons/achievements/Achievements.java | 19 +++- .../achievements/AchievementsActivity.java | 98 +++---------------- .../commons/achievements/FeaturedImages.java | 25 +++++ .../achievements/FeedbackResponse.java | 64 ++++++++++++ .../commons/di/CommonsApplicationModule.java | 2 +- .../free/nrw/commons/di/NetworkingModule.java | 15 ++- .../mwapi/ApacheHttpClientMediaWikiApi.java | 57 +++-------- .../free/nrw/commons/mwapi/MediaWikiApi.java | 9 +- .../fr/free/nrw/commons/quiz/QuizChecker.java | 59 +++++------ .../mwapi/ApacheHttpClientMediaWikiApiTest.kt | 5 +- 10 files changed, 182 insertions(+), 171 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/achievements/FeaturedImages.java create mode 100644 app/src/main/java/fr/free/nrw/commons/achievements/FeedbackResponse.java diff --git a/app/src/main/java/fr/free/nrw/commons/achievements/Achievements.java b/app/src/main/java/fr/free/nrw/commons/achievements/Achievements.java index 5fac8da9ae..55da22cd4a 100644 --- a/app/src/main/java/fr/free/nrw/commons/achievements/Achievements.java +++ b/app/src/main/java/fr/free/nrw/commons/achievements/Achievements.java @@ -1,7 +1,5 @@ package fr.free.nrw.commons.achievements; -import android.util.Log; - /** * represnts Achievements class ans stores all the parameters */ @@ -44,6 +42,23 @@ public Achievements(int uniqueUsedImages, this.revertCount = revertCount; } + /** + * Get Achievements object from FeedbackResponse + * + * @param response + * @return + */ + public static Achievements from(FeedbackResponse response) { + return new Achievements(response.getUniqueUsedImages(), + response.getArticlesUsingImages(), + response.getThanksReceived(), + response.getImagesEditedBySomeoneElse(), + response.getFeaturedImages().getQualityImages() + + response.getFeaturedImages().getFeaturedPicturesOnWikimediaCommons(), + 0, + response.getDeletedUploads()); + } + /** * Builder class for Achievements class */ diff --git a/app/src/main/java/fr/free/nrw/commons/achievements/AchievementsActivity.java b/app/src/main/java/fr/free/nrw/commons/achievements/AchievementsActivity.java index d25c1cd8f4..5aa5f5e489 100644 --- a/app/src/main/java/fr/free/nrw/commons/achievements/AchievementsActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/achievements/AchievementsActivity.java @@ -2,16 +2,9 @@ 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; @@ -20,7 +13,6 @@ 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; @@ -34,13 +26,10 @@ 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 java.util.Objects; import javax.inject.Inject; @@ -141,7 +130,6 @@ protected void onCreate(Bundle savedInstanceState) { hideLayouts(); setAchievements(); setUploadCount(); - setRevertCount(); initDrawer(); } @@ -201,61 +189,37 @@ void shareScreen(Bitmap bitmap) { * 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 - .getRevertRespObjectSingle(sessionManager.getCurrentAccount().name) + .getAchievements(Objects.requireNonNull(sessionManager.getCurrentAccount()).name) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( - object -> parseJsonRevertCount(object), - t -> Timber.e(t, "Fetching revert count failed") + response -> { + if (response != null) { + achievements = Achievements.from(response); + isRevertFetched = true; + isStatisticsFetched = true; + } + hideProgressBar(); + }, + t -> Timber.e(t, "Fetching achievements statisticss 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) + .getUploadCount(Objects.requireNonNull(sessionManager.getCurrentAccount()).name) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( - uploadCount -> setAchievementsUploadCount(uploadCount), + this::setAchievementsUploadCount, t -> Timber.e(t, "Fetching upload count failed") )); } @@ -293,33 +257,12 @@ private void setImageRevertPercentage(int notRevertPercentage){ 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 ){ + private void inflateAchievements(Achievements achievements) { thanksReceived.setText(Integer.toString(achievements.getThanksReceived())); imagesUsedByWikiProgessbar.setProgress (100*achievements.getUniqueUsedImages()/levelInfo.getMaxUniqueImages() ); @@ -393,17 +336,8 @@ public void showAlert(Bitmap 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.setPositiveButton("Proceed", (dialog, which) -> shareScreen(screenshot)); + alertadd.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel()); alertadd.show(); } diff --git a/app/src/main/java/fr/free/nrw/commons/achievements/FeaturedImages.java b/app/src/main/java/fr/free/nrw/commons/achievements/FeaturedImages.java new file mode 100644 index 0000000000..8b9992e285 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/achievements/FeaturedImages.java @@ -0,0 +1,25 @@ +package fr.free.nrw.commons.achievements; + +import com.google.gson.annotations.SerializedName; + +public class FeaturedImages { + + @SerializedName("Quality_images") + private final int qualityImages; + + @SerializedName("Featured_pictures_on_Wikimedia_Commons") + private final int featuredPicturesOnWikimediaCommons; + + public FeaturedImages(int qualityImages, int featuredPicturesOnWikimediaCommons) { + this.qualityImages = qualityImages; + this.featuredPicturesOnWikimediaCommons = featuredPicturesOnWikimediaCommons; + } + + public int getQualityImages() { + return qualityImages; + } + + public int getFeaturedPicturesOnWikimediaCommons() { + return featuredPicturesOnWikimediaCommons; + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/achievements/FeedbackResponse.java b/app/src/main/java/fr/free/nrw/commons/achievements/FeedbackResponse.java new file mode 100644 index 0000000000..37fea3e2dd --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/achievements/FeedbackResponse.java @@ -0,0 +1,64 @@ +package fr.free.nrw.commons.achievements; + +public class FeedbackResponse { + + private final String status; + private final int uniqueUsedImages; + private final int articlesUsingImages; + private final int deletedUploads; + private final FeaturedImages featuredImages; + private final int thanksReceived; + private final String user; + private final int imagesEditedBySomeoneElse; + + + public FeedbackResponse(String status, + int uniqueUsedImages, + int articlesUsingImages, + int deletedUploads, + FeaturedImages featuredImages, + int thanksReceived, + String user, + int imagesEditedBySomeoneElse) { + this.status = status; + this.uniqueUsedImages = uniqueUsedImages; + this.articlesUsingImages = articlesUsingImages; + this.deletedUploads = deletedUploads; + this.featuredImages = featuredImages; + this.thanksReceived = thanksReceived; + this.user = user; + this.imagesEditedBySomeoneElse = imagesEditedBySomeoneElse; + } + + public String getStatus() { + return status; + } + + public int getUniqueUsedImages() { + return uniqueUsedImages; + } + + public int getArticlesUsingImages() { + return articlesUsingImages; + } + + public int getDeletedUploads() { + return deletedUploads; + } + + public FeaturedImages getFeaturedImages() { + return featuredImages; + } + + public int getThanksReceived() { + return thanksReceived; + } + + public String getUser() { + return user; + } + + public int getImagesEditedBySomeoneElse() { + return imagesEditedBySomeoneElse; + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java index cf96193601..a6bc4f59d2 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java @@ -11,7 +11,6 @@ import dagger.Module; import dagger.Provides; - import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.auth.AccountUtil; import fr.free.nrw.commons.auth.SessionManager; @@ -22,6 +21,7 @@ import fr.free.nrw.commons.upload.UploadController; import fr.free.nrw.commons.wikidata.WikidataEditListener; import fr.free.nrw.commons.wikidata.WikidataEditListenerImpl; +import okhttp3.OkHttpClient; import static android.content.Context.MODE_PRIVATE; import static fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider.RECENT_SEARCH_AUTHORITY; 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 cd043e9502..953b7ecee5 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 @@ -7,6 +7,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import java.io.File; + import javax.inject.Named; import javax.inject.Singleton; @@ -15,6 +17,7 @@ import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi; import fr.free.nrw.commons.mwapi.MediaWikiApi; +import okhttp3.Cache; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; @@ -25,8 +28,11 @@ public class NetworkingModule { @Provides @Singleton - public OkHttpClient provideOkHttpClient() { - return new OkHttpClient.Builder().build(); + public OkHttpClient provideOkHttpClient(Context context) { + File dir = new File(context.getCacheDir(), "okHttpCache"); + return new OkHttpClient.Builder() + .cache(new Cache(dir, OK_HTTP_CACHE_SIZE)) + .build(); } @Provides @@ -34,8 +40,9 @@ public OkHttpClient provideOkHttpClient() { public MediaWikiApi provideMediaWikiApi(Context context, @Named("default_preferences") SharedPreferences defaultPreferences, @Named("category_prefs") SharedPreferences categoryPrefs, - Gson gson) { - return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, BuildConfig.WIKIDATA_API_HOST, defaultPreferences, categoryPrefs, gson); + Gson gson, + OkHttpClient okHttpClient) { + return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, BuildConfig.WIKIDATA_API_HOST, defaultPreferences, categoryPrefs, gson, okHttpClient); } @Provides diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java index b9a0468d9a..3218ccf18a 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java @@ -24,7 +24,6 @@ import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.util.EntityUtils; -import org.json.JSONObject; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -45,6 +44,7 @@ import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.Media; import fr.free.nrw.commons.PageTitle; +import fr.free.nrw.commons.achievements.FeedbackResponse; import fr.free.nrw.commons.auth.AccountUtil; import fr.free.nrw.commons.category.CategoryImageUtils; import fr.free.nrw.commons.category.QueryContinue; @@ -76,14 +76,17 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { private SharedPreferences defaultPreferences; private SharedPreferences categoryPreferences; private Gson gson; + private final OkHttpClient okHttpClient; public ApacheHttpClientMediaWikiApi(Context context, String apiURL, String wikidatApiURL, SharedPreferences defaultPreferences, SharedPreferences categoryPreferences, - Gson gson) { + Gson gson, + OkHttpClient okHttpClient) { this.context = context; + this.okHttpClient = okHttpClient; BasicHttpParams params = new BasicHttpParams(); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); @@ -963,12 +966,11 @@ public boolean isUserBlockedFromCommons() { /** * 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 + * @param userName MediaWiki user name * @return */ - @NonNull @Override - public Single getAchievements(String userName) { + public Single getAchievements(String userName) { final String fetchAchievementUrlTemplate = wikiMediaToolforgeUrl + "urbanecmbot/commonsmisc/feedback.py"; return Single.fromCallable(() -> { @@ -982,46 +984,19 @@ public Single getAchievements(String userName) { 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; + Response response = okHttpClient.newCall(request).execute(); + if (response != null && response.body() != null && response.isSuccessful()) { + String json = response.body().string(); + if (json == null) { + return null; + } + return gson.fromJson(json, FeedbackResponse.class); + } + return null; }); } - /** - * 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 getRevertRespObjectSingle(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")); diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java index 687e898473..805aab0565 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java @@ -4,13 +4,12 @@ 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; import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.achievements.FeedbackResponse; import fr.free.nrw.commons.notification.Notification; import io.reactivex.Observable; import io.reactivex.Single; @@ -98,13 +97,9 @@ public interface MediaWikiApi { @NonNull Single getUploadCount(String userName); - @NonNull - Single getRevertRespObjectSingle(String userName); - boolean isUserBlockedFromCommons(); - @NonNull - Single getAchievements(String userName); + Single getAchievements(String userName); void logout(); diff --git a/app/src/main/java/fr/free/nrw/commons/quiz/QuizChecker.java b/app/src/main/java/fr/free/nrw/commons/quiz/QuizChecker.java index b085636605..f34ef81ba1 100644 --- a/app/src/main/java/fr/free/nrw/commons/quiz/QuizChecker.java +++ b/app/src/main/java/fr/free/nrw/commons/quiz/QuizChecker.java @@ -1,11 +1,9 @@ package fr.free.nrw.commons.quiz; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.support.v7.app.AlertDialog.Builder; -import android.util.Log; import fr.free.nrw.commons.R; import fr.free.nrw.commons.WelcomeActivity; @@ -34,16 +32,16 @@ public class QuizChecker { private SharedPreferences revertPref; private SharedPreferences countPref; - private final int UPLOAD_COUNT_THRESHOLD = 5; - private final String REVERT_PERCENTAGE_FOR_MESSAGE = "50%"; + private static final int UPLOAD_COUNT_THRESHOLD = 5; + private static final String REVERT_PERCENTAGE_FOR_MESSAGE = "50%"; private final String REVERT_SHARED_PREFERENCE = "revertCount"; private final String UPLOAD_SHARED_PREFERENCE = "uploadCount"; /** * constructor to set the parameters for quiz - * @param context - * @param userName - * @param mediaWikiApi + * @param context context + * @param userName Commons user name + * @param mediaWikiApi instance of MediaWikiApi */ public QuizChecker(Context context, String userName, MediaWikiApi mediaWikiApi) { this.context = context; @@ -63,8 +61,7 @@ private void setUploadCount() { .getUploadCount(userName) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - uploadCount -> setTotalUploadCount(uploadCount), + .subscribe(this::setTotalUploadCount, t -> Timber.e(t, "Fetching upload count failed") )); } @@ -72,7 +69,7 @@ private void setUploadCount() { /** * set the sub Title of Contibutions Activity and * call function to check for quiz - * @param uploadCount + * @param uploadCount user's upload count */ private void setTotalUploadCount(int uploadCount) { totalUploadCount = uploadCount - countPref.getInt(UPLOAD_SHARED_PREFERENCE,0); @@ -89,17 +86,21 @@ private void setTotalUploadCount(int uploadCount) { */ private void setRevertCount() { compositeDisposable.add(mediaWikiApi - .getRevertRespObjectSingle(userName) + .getAchievements(userName) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( - object -> setRevertParameter(object.getInt("deletedUploads")) - )); + response -> { + if (response != null) { + setRevertParameter(response.getDeletedUploads()); + } + }, throwable -> Timber.e(throwable, "Fetching feedback failed")) + ); } /** * to calculate the number of images reverted after previous quiz - * @param revertCountFetched + * @param revertCountFetched count of deleted uploads */ private void setRevertParameter(int revertCountFetched) { revertCount = revertCountFetched - revertPref.getInt(REVERT_SHARED_PREFERENCE,0); @@ -130,30 +131,22 @@ private void calculateRevertParameter() { /** * Alert which prompts to quiz */ - public void callQuiz() { + private void callQuiz() { Builder alert = new Builder(context); alert.setTitle(context.getResources().getString(R.string.quiz)); alert.setMessage(context.getResources().getString(R.string.quiz_alert_message, REVERT_PERCENTAGE_FOR_MESSAGE)); - alert.setPositiveButton("Proceed", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - int newRevetSharedPrefs = revertCount+ revertPref.getInt(REVERT_SHARED_PREFERENCE,0); - revertPref.edit().putInt(REVERT_SHARED_PREFERENCE, newRevetSharedPrefs).apply(); - int newUploadCount = totalUploadCount + countPref.getInt(UPLOAD_SHARED_PREFERENCE,0); - countPref.edit().putInt(UPLOAD_SHARED_PREFERENCE,newUploadCount).apply(); - Intent i = new Intent(context, WelcomeActivity.class); - i.putExtra("isQuiz", true); - dialog.dismiss(); - context.startActivity(i); - } - }); - alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.cancel(); - } + alert.setPositiveButton("Proceed", (dialog, which) -> { + int newRevetSharedPrefs = revertCount + revertPref.getInt(REVERT_SHARED_PREFERENCE, 0); + revertPref.edit().putInt(REVERT_SHARED_PREFERENCE, newRevetSharedPrefs).apply(); + int newUploadCount = totalUploadCount + countPref.getInt(UPLOAD_SHARED_PREFERENCE, 0); + countPref.edit().putInt(UPLOAD_SHARED_PREFERENCE, newUploadCount).apply(); + Intent i = new Intent(context, WelcomeActivity.class); + i.putExtra("isQuiz", true); + dialog.dismiss(); + context.startActivity(i); }); + alert.setNegativeButton("Cancel", (dialogInterface, i) -> dialogInterface.cancel()); android.support.v7.app.AlertDialog dialog = alert.create(); dialog.show(); } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt index b070aed2a0..7b6ae96d13 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt @@ -6,6 +6,7 @@ import android.preference.PreferenceManager import com.google.gson.Gson import fr.free.nrw.commons.BuildConfig import fr.free.nrw.commons.TestCommonsApplication +import okhttp3.OkHttpClient import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.RecordedRequest @@ -30,14 +31,16 @@ class ApacheHttpClientMediaWikiApiTest { private lateinit var wikidataServer: MockWebServer private lateinit var sharedPreferences: SharedPreferences private lateinit var categoryPreferences: SharedPreferences + private lateinit var okHttpClient: OkHttpClient @Before fun setUp() { server = MockWebServer() wikidataServer = MockWebServer() + okHttpClient = OkHttpClient() sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) categoryPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) - testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", "http://" + wikidataServer.hostName + ":" + wikidataServer.port + "/", sharedPreferences, categoryPreferences, Gson()) + testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", "http://" + wikidataServer.hostName + ":" + wikidataServer.port + "/", sharedPreferences, categoryPreferences, Gson(), okHttpClient) testObject.setWikiMediaToolforgeUrl("http://" + server.hostName + ":" + server.port + "/") } From 325e0168e3e950df8fa8d53e3aa5c23312d26ef3 Mon Sep 17 00:00:00 2001 From: Josephine Lim Date: Fri, 7 Sep 2018 00:37:47 +1000 Subject: [PATCH 7/9] Set Traceur to only work in DEBUG mode (#1884) --- .../main/java/fr/free/nrw/commons/CommonsApplication.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index 0e68af83c4..5fcab1d0b2 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -72,7 +72,11 @@ public class CommonsApplication extends MultiDexApplication { @Override public void onCreate() { super.onCreate(); - Traceur.enableLogging(); + if (BuildConfig.DEBUG) { + //FIXME: Traceur should be disabled for release builds until error fixed + //See https://github.com/commons-app/apps-android-commons/issues/1877 + Traceur.enableLogging(); + } ApplicationlessInjection .getInstance(this) From cc74f3add7c45f56ce6cc65ec953fd6c64d41fd0 Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Thu, 6 Sep 2018 21:27:40 +0530 Subject: [PATCH 8/9] Bug fix for uploaded images count in achievements activity (#1885) --- .../commons/achievements/Achievements.java | 59 ------------------- .../achievements/AchievementsActivity.java | 45 ++++++++------ app/src/main/res/values/strings.xml | 2 + 3 files changed, 28 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/achievements/Achievements.java b/app/src/main/java/fr/free/nrw/commons/achievements/Achievements.java index 55da22cd4a..98fe099da9 100644 --- a/app/src/main/java/fr/free/nrw/commons/achievements/Achievements.java +++ b/app/src/main/java/fr/free/nrw/commons/achievements/Achievements.java @@ -59,65 +59,6 @@ public static Achievements from(FeedbackResponse response) { response.getDeletedUploads()); } - /** - * 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 diff --git a/app/src/main/java/fr/free/nrw/commons/achievements/AchievementsActivity.java b/app/src/main/java/fr/free/nrw/commons/achievements/AchievementsActivity.java index 5aa5f5e489..1bc1cc27dc 100644 --- a/app/src/main/java/fr/free/nrw/commons/achievements/AchievementsActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/achievements/AchievementsActivity.java @@ -54,10 +54,7 @@ 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) @@ -129,7 +126,6 @@ protected void onCreate(Bundle savedInstanceState) { progressBar.setVisibility(View.VISIBLE); hideLayouts(); setAchievements(); - setUploadCount(); initDrawer(); } @@ -189,7 +185,6 @@ void shareScreen(Bitmap bitmap) { * which then calls parseJson when results are fetched */ private void setAchievements() { - if(checkAccount()) { compositeDisposable.add(mediaWikiApi .getAchievements(Objects.requireNonNull(sessionManager.getCurrentAccount()).name) @@ -198,29 +193,42 @@ private void setAchievements() { .subscribe( response -> { if (response != null) { - achievements = Achievements.from(response); - isRevertFetched = true; - isStatisticsFetched = true; + setUploadCount(Achievements.from(response)); + } else { + onError(); } - hideProgressBar(); }, - t -> Timber.e(t, "Fetching achievements statisticss failed") + t -> { + Timber.e(t, "Fetching achievements statistics failed"); + onError(); + } )); } } + /** + * Shows a generic error toast when error occurs while loading achievements or uploads + */ + private void onError() { + ViewUtil.showLongToast(this, getResources().getString(R.string.error_occurred)); + progressBar.setVisibility(View.GONE); + } + /** * used to the count of images uploaded by user */ - private void setUploadCount() { + private void setUploadCount(Achievements achievements) { if(checkAccount()) { compositeDisposable.add(mediaWikiApi .getUploadCount(Objects.requireNonNull(sessionManager.getCurrentAccount()).name) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( - this::setAchievementsUploadCount, - t -> Timber.e(t, "Fetching upload count failed") + uploadCount -> setAchievementsUploadCount(achievements, uploadCount), + t -> { + Timber.e(t, "Fetching upload count failed"); + onError(); + } )); } } @@ -229,10 +237,9 @@ private void setUploadCount() { * used to set achievements upload count and call hideProgressbar * @param uploadCount */ - private void setAchievementsUploadCount(int uploadCount){ + private void setAchievementsUploadCount(Achievements achievements, int uploadCount) { achievements.setImagesUploaded(uploadCount); - isUploadFetched = true; - hideProgressBar(); + hideProgressBar(achievements); } /** @@ -293,8 +300,8 @@ public static void startYourself(Context context) { /** * to hide progressbar */ - private void hideProgressBar() { - if (progressBar != null && isUploadFetched && isStatisticsFetched && isRevertFetched) { + private void hideProgressBar(Achievements achievements) { + if (progressBar != null) { levelInfo = LevelController.LevelInfo.from(achievements.getImagesUploaded(), achievements.getUniqueUsedImages(), achievements.getNotRevertPercentage()); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0dacddd39..60c5343ba6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -341,4 +341,6 @@ The number of images you have uploaded to Commons, via any upload software The percentage of images you have uploaded to Commons that were not deleted The number of images you have uploaded to Commons that were used in Wikimedia articles + + Error occurred! From d3dfdc8c9c5a2db765f9e7fe29e95ba7cc8d98ac Mon Sep 17 00:00:00 2001 From: Josephine Lim Date: Fri, 7 Sep 2018 02:34:57 +1000 Subject: [PATCH 9/9] Versioning and changelog for v2.8.3 (#1886) * Update changelog.md * Versioning for v2.8.3 --- CHANGELOG.md | 5 +++++ app/build.gradle | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3ecfa8af5..87f4a9cfe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Wikimedia Commons for Android +## v2.8.3 +- Fixed issues with session tokens not being cleared in 2FA, which should reduce p18 edit failures as well +- Fixed crash caused by bug in fetching revert count +- Fixed crash potentially caused by Traceur library + ## v2.8.2 - Fixed bug with uploads sent via Share being given .jpeg extensions and overwriting files of the same name diff --git a/app/build.gradle b/app/build.gradle index 16dad0e6bd..9f9ff00ed0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -90,8 +90,8 @@ android { defaultConfig { applicationId 'fr.free.nrw.commons' - versionCode 89 - versionName '2.8.2' + versionCode 90 + versionName '2.8.3' setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) minSdkVersion project.minSdkVersion