From 088dd2479e56523591085d5bb0a076c2903d1813 Mon Sep 17 00:00:00 2001 From: u7479759 Date: Thu, 21 Nov 2024 23:42:54 +1100 Subject: [PATCH] Changed to data classes, and added immutability (#5905) Co-authored-by: Jinniu Du <127721018+Donutcheese@users.noreply.github.com> --- .../profile/achievements/Achievements.kt | 121 ++++------------ .../achievements/AchievementsFragment.java | 134 ++++++++++-------- .../profile/achievements/FeaturedImages.kt | 2 +- 3 files changed, 104 insertions(+), 153 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/profile/achievements/Achievements.kt b/app/src/main/java/fr/free/nrw/commons/profile/achievements/Achievements.kt index 861040fcff..7b23db2cd9 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/achievements/Achievements.kt +++ b/app/src/main/java/fr/free/nrw/commons/profile/achievements/Achievements.kt @@ -1,104 +1,45 @@ package fr.free.nrw.commons.profile.achievements /** - * Represents Achievements class and stores all the parameters + * Represents Achievements data class and stores all the parameters. + * Immutable version with default values for optional properties. */ -class Achievements { +data class Achievements( + val uniqueUsedImages: Int = 0, + val articlesUsingImages: Int = 0, + val thanksReceived: Int = 0, + val featuredImages: Int = 0, + val qualityImages: Int = 0, + val imagesUploaded: Int = 0, + val revertCount: Int = 0 +) { /** - * The count of unique images used by the wiki. - * @return The count of unique images used. - * @param uniqueUsedImages The count to set for unique images used. - */ - var uniqueUsedImages = 0 - private var articlesUsingImages = 0 - - /** - * The count of thanks received. - * @return The count of thanks received. - * @param thanksReceived The count to set for thanks received. - */ - var thanksReceived = 0 - - /** - * The count of featured images. - * @return The count of featured images. - * @param featuredImages The count to set for featured images. - */ - var featuredImages = 0 - - /** - * The count of quality images. - * @return The count of quality images. - * @param qualityImages The count to set for quality images. - */ - var qualityImages = 0 - - /** - * The count of images uploaded. - * @return The count of images uploaded. - * @param imagesUploaded The count to set for images uploaded. - */ - var imagesUploaded = 0 - private var revertCount = 0 - - constructor() {} - - /** - * constructor for achievements class to set its data members - * @param uniqueUsedImages - * @param articlesUsingImages - * @param thanksReceived - * @param featuredImages - * @param imagesUploaded - * @param revertCount - */ - constructor( - uniqueUsedImages: Int, - articlesUsingImages: Int, - thanksReceived: Int, - featuredImages: Int, - qualityImages: Int, - imagesUploaded: Int, - revertCount: Int, - ) { - this.uniqueUsedImages = uniqueUsedImages - this.articlesUsingImages = articlesUsingImages - this.thanksReceived = thanksReceived - this.featuredImages = featuredImages - this.qualityImages = qualityImages - this.imagesUploaded = imagesUploaded - this.revertCount = revertCount - } - - /** - * used to calculate the percentages of images that haven't been reverted - * @return + * Used to calculate the percentages of images that haven't been reverted. + * Returns 100 if imagesUploaded is 0 to avoid division by zero. */ val notRevertPercentage: Int - get() = - try { - (imagesUploaded - revertCount) * 100 / imagesUploaded - } catch (divideByZero: ArithmeticException) { - 100 - } + get() = if (imagesUploaded > 0) { + (imagesUploaded - revertCount) * 100 / imagesUploaded + } else { + 100 + } companion object { /** - * Get Achievements object from FeedbackResponse + * Get Achievements object from FeedbackResponse. * - * @param response - * @return + * @param response The feedback response to convert. + * @return An Achievements object with values from the response. */ @JvmStatic - fun from(response: FeedbackResponse): Achievements = - Achievements( - response.uniqueUsedImages, - response.articlesUsingImages, - response.thanksReceived, - response.featuredImages.featuredPicturesOnWikimediaCommons, - response.featuredImages.qualityImages, - 0, - response.deletedUploads, - ) + fun from(response: FeedbackResponse): Achievements = Achievements( + uniqueUsedImages = response.uniqueUsedImages, + articlesUsingImages = response.articlesUsingImages, + thanksReceived = response.thanksReceived, + featuredImages = response.featuredImages.featuredPicturesOnWikimediaCommons, + qualityImages = response.featuredImages.qualityImages, + imagesUploaded = 0, // Assuming imagesUploaded should be 0 + revertCount = response.deletedUploads + ) } -} +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementsFragment.java b/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementsFragment.java index f44b7eb6d7..ef6a323b2e 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/profile/achievements/AchievementsFragment.java @@ -105,7 +105,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // Used for the setting the size of imageView at runtime ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) - binding.achievementBadgeImage.getLayoutParams(); + binding.achievementBadgeImage.getLayoutParams(); params.height = (int) (height * BADGE_IMAGE_HEIGHT_RATIO); params.width = (int) (width * BADGE_IMAGE_WIDTH_RATIO); binding.achievementBadgeImage.requestLayout(); @@ -186,37 +186,37 @@ private void setAchievements() { try{ compositeDisposable.add(okHttpJsonApiClient - .getAchievements(Objects.requireNonNull(userName)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - response -> { - if (response != null) { - setUploadCount(Achievements.from(response)); - } else { - Timber.d("success"); - binding.layoutImageReverts.setVisibility(View.INVISIBLE); - binding.achievementBadgeImage.setVisibility(View.INVISIBLE); - // If the number of edits made by the user are more than 150,000 - // in some cases such high number of wiki edit counts cause the - // achievements calculator to fail in some cases, for more details - // refer Issue: #3295 - if (numberOfEdits <= 150000) { - showSnackBarWithRetry(false); - } else { - showSnackBarWithRetry(true); - } - } - }, - t -> { - Timber.e(t, "Fetching achievements statistics failed"); - if (numberOfEdits <= 150000) { - showSnackBarWithRetry(false); - } else { - showSnackBarWithRetry(true); - } + .getAchievements(Objects.requireNonNull(userName)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + response -> { + if (response != null) { + setUploadCount(Achievements.from(response)); + } else { + Timber.d("success"); + binding.layoutImageReverts.setVisibility(View.INVISIBLE); + binding.achievementBadgeImage.setVisibility(View.INVISIBLE); + // If the number of edits made by the user are more than 150,000 + // in some cases such high number of wiki edit counts cause the + // achievements calculator to fail in some cases, for more details + // refer Issue: #3295 + if (numberOfEdits <= 150000) { + showSnackBarWithRetry(false); + } else { + showSnackBarWithRetry(true); } - )); + } + }, + t -> { + Timber.e(t, "Fetching achievements statistics failed"); + if (numberOfEdits <= 150000) { + showSnackBarWithRetry(false); + } else { + showSnackBarWithRetry(true); + } + } + )); } catch (Exception e){ Timber.d(e+"success"); @@ -233,15 +233,15 @@ private void setWikidataEditCount() { return; } compositeDisposable.add(okHttpJsonApiClient - .getWikidataEdits(userName) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(edits -> { - numberOfEdits = edits; - binding.wikidataEdits.setText(String.valueOf(edits)); - }, e -> { - Timber.e("Error:" + e); - })); + .getWikidataEdits(userName) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(edits -> { + numberOfEdits = edits; + binding.wikidataEdits.setText(String.valueOf(edits)); + }, e -> { + Timber.e("Error:" + e); + })); } /** @@ -255,11 +255,11 @@ private void showSnackBarWithRetry(boolean tooManyAchievements) { if (tooManyAchievements) { binding.progressBar.setVisibility(View.GONE); ViewUtil.showDismissibleSnackBar(getActivity().findViewById(android.R.id.content), - R.string.achievements_fetch_failed_ultimate_achievement, R.string.retry, view -> setAchievements()); + R.string.achievements_fetch_failed_ultimate_achievement, R.string.retry, view -> setAchievements()); } else { binding.progressBar.setVisibility(View.GONE); ViewUtil.showDismissibleSnackBar(getActivity().findViewById(android.R.id.content), - R.string.achievements_fetch_failed, R.string.retry, view -> setAchievements()); + R.string.achievements_fetch_failed, R.string.retry, view -> setAchievements()); } } @@ -277,16 +277,16 @@ private void onError() { private void setUploadCount(Achievements achievements) { if (checkAccount()) { compositeDisposable.add(okHttpJsonApiClient - .getUploadCount(Objects.requireNonNull(userName)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - uploadCount -> setAchievementsUploadCount(achievements, uploadCount), - t -> { - Timber.e(t, "Fetching upload count failed"); - onError(); - } - )); + .getUploadCount(Objects.requireNonNull(userName)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + uploadCount -> setAchievementsUploadCount(achievements, uploadCount), + t -> { + Timber.e(t, "Fetching upload count failed"); + onError(); + } + )); } } @@ -295,8 +295,18 @@ private void setUploadCount(Achievements achievements) { * @param uploadCount */ private void setAchievementsUploadCount(Achievements achievements, int uploadCount) { - achievements.setImagesUploaded(uploadCount); - hideProgressBar(achievements); + // Create a new instance of Achievements with updated imagesUploaded + Achievements updatedAchievements = new Achievements( + achievements.getUniqueUsedImages(), + achievements.getArticlesUsingImages(), + achievements.getThanksReceived(), + achievements.getFeaturedImages(), + achievements.getQualityImages(), + uploadCount, // Update imagesUploaded with new value + achievements.getRevertCount() + ); + + hideProgressBar(updatedAchievements); } /** @@ -309,7 +319,7 @@ private void setUploadProgress(int uploadCount){ }else { binding.imagesUploadedProgressbar.setVisibility(View.VISIBLE); binding.imagesUploadedProgressbar.setProgress - (100*uploadCount/levelInfo.getMaxUploadCount()); + (100*uploadCount/levelInfo.getMaxUploadCount()); binding.tvUploadedImages.setText (uploadCount + "/" + levelInfo.getMaxUploadCount()); } @@ -318,8 +328,8 @@ private void setUploadProgress(int uploadCount){ private void setZeroAchievements() { String message = !Objects.equals(sessionManager.getUserName(), userName) ? - getString(R.string.no_achievements_yet, userName) : - getString(R.string.you_have_no_achievements_yet); + getString(R.string.no_achievements_yet, userName) : + getString(R.string.you_have_no_achievements_yet); DialogUtil.showAlertDialog(getActivity(), null, message, @@ -357,7 +367,7 @@ private void inflateAchievements(Achievements achievements) { // binding.imagesUsedByWikiProgressBar.setVisibility(View.VISIBLE); binding.thanksReceived.setText(String.valueOf(achievements.getThanksReceived())); binding.imagesUsedByWikiProgressBar.setProgress - (100 * achievements.getUniqueUsedImages() / levelInfo.getMaxUniqueImages()); + (100 * achievements.getUniqueUsedImages() / levelInfo.getMaxUniqueImages()); binding.tvWikiPb.setText(achievements.getUniqueUsedImages() + "/" + levelInfo.getMaxUniqueImages()); binding.imageFeatured.setText(String.valueOf(achievements.getFeaturedImages())); @@ -366,7 +376,7 @@ private void inflateAchievements(Achievements achievements) { levelUpInfoString += " " + levelInfo.getLevelNumber(); binding.achievementLevel.setText(levelUpInfoString); binding.achievementBadgeImage.setImageDrawable(VectorDrawableCompat.create(getResources(), R.drawable.badge, - new ContextThemeWrapper(getActivity(), levelInfo.getLevelStyle()).getTheme())); + new ContextThemeWrapper(getActivity(), levelInfo.getLevelStyle()).getTheme())); binding.achievementBadgeText.setText(Integer.toString(levelInfo.getLevelNumber())); BasicKvStore store = new BasicKvStore(this.getContext(), userName); store.putString("userAchievementsLevel", Integer.toString(levelInfo.getLevelNumber())); @@ -378,8 +388,8 @@ private void inflateAchievements(Achievements achievements) { private void hideProgressBar(Achievements achievements) { if (binding.progressBar != null) { levelInfo = LevelController.LevelInfo.from(achievements.getImagesUploaded(), - achievements.getUniqueUsedImages(), - achievements.getNotRevertPercentage()); + achievements.getUniqueUsedImages(), + achievements.getNotRevertPercentage()); inflateAchievements(achievements); setUploadProgress(achievements.getImagesUploaded()); setImageRevertPercentage(achievements.getNotRevertPercentage()); @@ -479,4 +489,4 @@ private boolean checkAccount(){ } return true; } -} +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/profile/achievements/FeaturedImages.kt b/app/src/main/java/fr/free/nrw/commons/profile/achievements/FeaturedImages.kt index 4784103fdb..2a336d3496 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/achievements/FeaturedImages.kt +++ b/app/src/main/java/fr/free/nrw/commons/profile/achievements/FeaturedImages.kt @@ -6,7 +6,7 @@ import com.google.gson.annotations.SerializedName * Represents Featured Images on WikiMedia Commons platform * Used by Achievements and FeedbackResponse (objects) of the user */ -class FeaturedImages( +data class FeaturedImages( @field:SerializedName("Quality_images") val qualityImages: Int, @field:SerializedName("Featured_pictures_on_Wikimedia_Commons") val featuredPicturesOnWikimediaCommons: Int, )