From 5e35db159df5aac9069f1f5afaa4acbc676b158b Mon Sep 17 00:00:00 2001 From: Paul Hawke Date: Sat, 11 Nov 2023 23:39:59 -0600 Subject: [PATCH] Remove butterknife from achievements fragment (#5382) * Replace butterknife view bindings * Migrated onClick listeners, and removed Butterknife --- .../achievements/AchievementsFragment.java | 219 +++++++----------- .../AchievementsFragmentUnitTests.kt | 108 ++------- 2 files changed, 100 insertions(+), 227 deletions(-) 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 5bb955046..b2bcfc26d 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 @@ -15,18 +15,17 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.view.ContextThemeWrapper; import androidx.appcompat.widget.AppCompatTextView; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; import com.dinuscxj.progressbar.CircleProgressBar; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.auth.SessionManager; +import fr.free.nrw.commons.databinding.FragmentAchievementsBinding; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient; import fr.free.nrw.commons.utils.ConfigUtils; @@ -62,86 +61,19 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { private LevelController.LevelInfo levelInfo; - @BindView(R.id.achievement_badge_image) - ImageView imageView; - - @BindView(R.id.achievement_badge_text) - TextView badgeText; - - @BindView(R.id.achievement_level) - TextView levelNumber; - - @BindView(R.id.thanks_received) - TextView thanksReceived; - - @BindView(R.id.images_uploaded_progressbar) - CircleProgressBar imagesUploadedProgressbar; - - @BindView(R.id.tv_uploaded_images) - AppCompatTextView uploadedImagesTextview; - - @BindView(R.id.images_used_by_wiki_progress_bar) - CircleProgressBar imagesUsedByWikiProgressBar; - - @BindView(R.id.tv_wiki_pb) - AppCompatTextView imagesUsedByWikiTextview; - - @BindView(R.id.image_reverts_progressbar) - CircleProgressBar imageRevertsProgressbar; - - @BindView(R.id.image_featured) - TextView imagesFeatured; - - @BindView(R.id.quality_images) - TextView tvQualityImages; - - @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; - - @BindView(R.id.images_used_by_wiki_text) - TextView imageByWikiText; - - @BindView(R.id.images_reverted_text) - TextView imageRevertedText; - - @BindView(R.id.images_upload_text_param) - TextView imageUploadedText; - - @BindView(R.id.wikidata_edits) - TextView wikidataEditsText; - - @BindView(R.id.tv_achievements_of_user) - AppCompatTextView tvAchievementsOfUser; - @Inject SessionManager sessionManager; @Inject OkHttpJsonApiClient okHttpJsonApiClient; + private FragmentAchievementsBinding binding; + private CompositeDisposable compositeDisposable = new CompositeDisposable(); // To keep track of the number of wiki edits made by a user private int numberOfEdits = 0; - // menu item for action bar - private MenuItem item; - private String userName; @Override @@ -160,8 +92,17 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_achievements, container, false); - ButterKnife.bind(this, rootView); + binding = FragmentAchievementsBinding.inflate(inflater, container, false); + View rootView = binding.getRoot(); + + binding.achievementInfo.setOnClickListener(view -> showInfoDialog()); + binding.imagesUploadInfo.setOnClickListener(view -> showUploadInfo()); + binding.imagesRevertedInfo.setOnClickListener(view -> showRevertedInfo()); + binding.imagesUsedByWikiInfo.setOnClickListener(view -> showUsedByWikiInfo()); + binding.imagesNearbyInfo.setOnClickListener(view -> showImagesViaNearbyInfo()); + binding.imagesFeaturedInfo.setOnClickListener(view -> showFeaturedImagesInfo()); + binding.thanksReceivedInfo.setOnClickListener(view -> showThanksReceivedInfo()); + binding.qualityImagesInfo.setOnClickListener(view -> showQualityImagesInfo()); // DisplayMetrics used to fetch the size of the screen DisplayMetrics displayMetrics = new DisplayMetrics(); @@ -171,33 +112,33 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { // Used for the setting the size of imageView at runtime ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) - imageView.getLayoutParams(); + binding.achievementBadgeImage.getLayoutParams(); params.height = (int) (height * BADGE_IMAGE_HEIGHT_RATIO); params.width = (int) (width * BADGE_IMAGE_WIDTH_RATIO); - imageView.requestLayout(); - progressBar.setVisibility(View.VISIBLE); + binding.achievementBadgeImage.requestLayout(); + binding.progressBar.setVisibility(View.VISIBLE); setHasOptionsMenu(true); // Set the initial value of WikiData edits to 0 - wikidataEditsText.setText("0"); - if(sessionManager.getUserName().equals(userName)){ - tvAchievementsOfUser.setVisibility(View.GONE); + binding.wikidataEdits.setText("0"); + if(sessionManager.getUserName() == null || sessionManager.getUserName().equals(userName)){ + binding.tvAchievementsOfUser.setVisibility(View.GONE); }else{ - tvAchievementsOfUser.setVisibility(View.VISIBLE); - tvAchievementsOfUser.setText(getString(R.string.achievements_of_user,userName)); + binding.tvAchievementsOfUser.setVisibility(View.VISIBLE); + binding.tvAchievementsOfUser.setText(getString(R.string.achievements_of_user,userName)); } // Achievements currently unimplemented in Beta flavor. Skip all API calls. if(ConfigUtils.isBetaFlavour()) { - progressBar.setVisibility(View.GONE); - imageByWikiText.setText(R.string.no_image); - imageRevertedText.setText(R.string.no_image_reverted); - imageUploadedText.setText(R.string.no_image_uploaded); - wikidataEditsText.setText("0"); - imagesFeatured.setText("0"); - tvQualityImages.setText("0"); - thanksReceived.setText("0"); + binding.progressBar.setVisibility(View.GONE); + binding.imagesUsedByWikiText.setText(R.string.no_image); + binding.imagesRevertedText.setText(R.string.no_image_reverted); + binding.imagesUploadTextParam.setText(R.string.no_image_uploaded); + binding.wikidataEdits.setText("0"); + binding.imageFeatured.setText("0"); + binding.qualityImages.setText("0"); + binding.achievementLevel.setText("0"); setMenuVisibility(true); return rootView; } @@ -206,6 +147,12 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { return rootView; } + @Override + public void onDestroyView() { + binding = null; + super.onDestroyView(); + } + @Override public void setMenuVisibility(boolean visible) { super.setMenuVisibility(visible); @@ -230,8 +177,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { /** * To invoke the AlertDialog on clicking info button */ - @OnClick(R.id.achievement_info) - public void showInfoDialog(){ + protected void showInfoDialog(){ launchAlert( getResources().getString(R.string.Achievements), getResources().getString(R.string.achievements_info_message)); @@ -242,7 +188,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { * which then calls parseJson when results are fetched */ private void setAchievements() { - progressBar.setVisibility(View.VISIBLE); + binding.progressBar.setVisibility(View.VISIBLE); if (checkAccount()) { try{ @@ -256,8 +202,8 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { setUploadCount(Achievements.from(response)); } else { Timber.d("success"); - layoutImageReverts.setVisibility(View.INVISIBLE); - imageView.setVisibility(View.INVISIBLE); + 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 @@ -299,7 +245,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { .observeOn(AndroidSchedulers.mainThread()) .subscribe(edits -> { numberOfEdits = edits; - wikidataEditsText.setText(String.valueOf(edits)); + binding.wikidataEdits.setText(String.valueOf(edits)); }, e -> { Timber.e("Error:" + e); })); @@ -314,11 +260,11 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { */ private void showSnackBarWithRetry(boolean tooManyAchievements) { if (tooManyAchievements) { - progressBar.setVisibility(View.GONE); + 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()); } else { - progressBar.setVisibility(View.GONE); + binding.progressBar.setVisibility(View.GONE); ViewUtil.showDismissibleSnackBar(getActivity().findViewById(android.R.id.content), R.string.achievements_fetch_failed, R.string.retry, view -> setAchievements()); } @@ -329,7 +275,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { */ private void onError() { ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.error_occurred)); - progressBar.setVisibility(View.GONE); + binding.progressBar.setVisibility(View.GONE); } /** @@ -368,10 +314,10 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { if (uploadCount==0){ setZeroAchievements(); }else { - imagesUploadedProgressbar.setVisibility(View.VISIBLE); - imagesUploadedProgressbar.setProgress + binding.imagesUploadedProgressbar.setVisibility(View.VISIBLE); + binding.imagesUploadedProgressbar.setProgress (100*uploadCount/levelInfo.getMaxUploadCount()); - uploadedImagesTextview.setText + binding.tvUploadedImages.setText (uploadCount + "/" + levelInfo.getMaxUploadCount()); } @@ -387,14 +333,14 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { getString(R.string.ok), () -> {}, true); - imagesUploadedProgressbar.setVisibility(View.INVISIBLE); - imageRevertsProgressbar.setVisibility(View.INVISIBLE); - imagesUsedByWikiProgressBar.setVisibility(View.INVISIBLE); - imageView.setVisibility(View.INVISIBLE); - imageByWikiText.setText(R.string.no_image); - imageRevertedText.setText(R.string.no_image_reverted); - imageUploadedText.setText(R.string.no_image_uploaded); - imageView.setVisibility(View.INVISIBLE); + binding.imagesUploadedProgressbar.setVisibility(View.INVISIBLE); + binding.imageRevertsProgressbar.setVisibility(View.INVISIBLE); + binding.imagesUsedByWikiProgressBar.setVisibility(View.INVISIBLE); + binding.achievementBadgeImage.setVisibility(View.INVISIBLE); + binding.imagesUsedByWikiText.setText(R.string.no_image); + binding.imagesRevertedText.setText(R.string.no_image_reverted); + binding.imagesUploadTextParam.setText(R.string.no_image_uploaded); + binding.achievementBadgeImage.setVisibility(View.INVISIBLE); } /** @@ -402,11 +348,11 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { * @param notRevertPercentage */ private void setImageRevertPercentage(int notRevertPercentage){ - imageRevertsProgressbar.setVisibility(View.VISIBLE); - imageRevertsProgressbar.setProgress(notRevertPercentage); + binding.imageRevertsProgressbar.setVisibility(View.VISIBLE); + binding.imageRevertsProgressbar.setProgress(notRevertPercentage); String revertPercentage = Integer.toString(notRevertPercentage); - imageRevertsProgressbar.setProgressTextFormatPattern(revertPercentage + "%%"); - imagesRevertLimitText.setText(getResources().getString(R.string.achievements_revert_limit_message)+ levelInfo.getMinNonRevertPercentage() + "%"); + binding.imageRevertsProgressbar.setProgressTextFormatPattern(revertPercentage + "%%"); + binding.imagesRevertLimitText.setText(getResources().getString(R.string.achievements_revert_limit_message)+ levelInfo.getMinNonRevertPercentage() + "%"); } /** @@ -415,90 +361,81 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment { * @param achievements */ private void inflateAchievements(Achievements achievements) { - imagesUsedByWikiProgressBar.setVisibility(View.VISIBLE); - thanksReceived.setText(String.valueOf(achievements.getThanksReceived())); - imagesUsedByWikiProgressBar.setProgress + binding.imagesUsedByWikiProgressBar.setVisibility(View.VISIBLE); + binding.achievementLevel.setText(String.valueOf(achievements.getThanksReceived())); + binding.imagesUsedByWikiProgressBar.setProgress (100 * achievements.getUniqueUsedImages() / levelInfo.getMaxUniqueImages()); - if(imagesUsedByWikiTextview != null) { - imagesUsedByWikiTextview.setText + if(binding.tvWikiPb != null) { + binding.tvWikiPb.setText (achievements.getUniqueUsedImages() + "/" + levelInfo.getMaxUniqueImages()); } - imagesFeatured.setText(String.valueOf(achievements.getFeaturedImages())); - tvQualityImages.setText(String.valueOf(achievements.getQualityImages())); + binding.imageFeatured.setText(String.valueOf(achievements.getFeaturedImages())); + binding.qualityImages.setText(String.valueOf(achievements.getQualityImages())); String levelUpInfoString = getString(R.string.level).toUpperCase(); levelUpInfoString += " " + levelInfo.getLevelNumber(); - levelNumber.setText(levelUpInfoString); - imageView.setImageDrawable(VectorDrawableCompat.create(getResources(), R.drawable.badge, + binding.achievementLevel.setText(levelUpInfoString); + binding.achievementBadgeImage.setImageDrawable(VectorDrawableCompat.create(getResources(), R.drawable.badge, new ContextThemeWrapper(getActivity(), levelInfo.getLevelStyle()).getTheme())); - badgeText.setText(Integer.toString(levelInfo.getLevelNumber())); + binding.achievementBadgeText.setText(Integer.toString(levelInfo.getLevelNumber())); } /** * to hide progressbar */ private void hideProgressBar(Achievements achievements) { - if (progressBar != null) { + if (binding.progressBar != null) { levelInfo = LevelController.LevelInfo.from(achievements.getImagesUploaded(), achievements.getUniqueUsedImages(), achievements.getNotRevertPercentage()); inflateAchievements(achievements); setUploadProgress(achievements.getImagesUploaded()); setImageRevertPercentage(achievements.getNotRevertPercentage()); - progressBar.setVisibility(View.GONE); - item.setVisible(true); + binding.progressBar.setVisibility(View.GONE); } } - - @OnClick(R.id.images_upload_info) - public void showUploadInfo(){ + protected void showUploadInfo(){ launchAlertWithHelpLink( getResources().getString(R.string.images_uploaded), getResources().getString(R.string.images_uploaded_explanation), IMAGES_UPLOADED_URL); } - @OnClick(R.id.images_reverted_info) - public void showRevertedInfo(){ + protected void showRevertedInfo(){ launchAlertWithHelpLink( getResources().getString(R.string.image_reverts), getResources().getString(R.string.images_reverted_explanation), IMAGES_REVERT_URL); } - @OnClick(R.id.images_used_by_wiki_info) - public void showUsedByWikiInfo(){ + protected void showUsedByWikiInfo(){ launchAlertWithHelpLink( getResources().getString(R.string.images_used_by_wiki), getResources().getString(R.string.images_used_explanation), IMAGES_USED_URL); } - @OnClick(R.id.images_nearby_info) - public void showImagesViaNearbyInfo(){ + protected void showImagesViaNearbyInfo(){ launchAlertWithHelpLink( getResources().getString(R.string.statistics_wikidata_edits), getResources().getString(R.string.images_via_nearby_explanation), IMAGES_NEARBY_PLACES_URL); } - @OnClick(R.id.images_featured_info) - public void showFeaturedImagesInfo(){ + protected void showFeaturedImagesInfo(){ launchAlertWithHelpLink( getResources().getString(R.string.statistics_featured), getResources().getString(R.string.images_featured_explanation), IMAGES_FEATURED_URL); } - @OnClick(R.id.thanks_received_info) - public void showThanksReceivedInfo(){ + protected void showThanksReceivedInfo(){ launchAlertWithHelpLink( getResources().getString(R.string.statistics_thanks), getResources().getString(R.string.thanks_received_explanation), THANKS_URL); } - @OnClick(R.id.quality_images_info) public void showQualityImagesInfo() { launchAlertWithHelpLink( getResources().getString(R.string.statistics_quality), diff --git a/app/src/test/kotlin/fr/free/nrw/commons/profile/achievements/AchievementsFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/profile/achievements/AchievementsFragmentUnitTests.kt index 42a73a5cc..5bbe49f29 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/profile/achievements/AchievementsFragmentUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/profile/achievements/AchievementsFragmentUnitTests.kt @@ -1,5 +1,6 @@ package fr.free.nrw.commons.profile.achievements +import android.accounts.Account import android.content.Context import android.os.Looper import android.view.LayoutInflater @@ -55,109 +56,37 @@ class AchievementsFragmentUnitTests { private lateinit var layoutInflater: LayoutInflater - @Mock - private lateinit var imageView: ImageView - - @Mock - private lateinit var badgeText: TextView - - @Mock - private lateinit var levelNumber: TextView - - @Mock - private lateinit var thanksReceived: TextView - - @Mock - private lateinit var imagesUploadedProgressbar: CircleProgressBar - - @Mock - private lateinit var imagesUsedByWikiProgressBar: CircleProgressBar - - @Mock - private lateinit var imageRevertsProgressbar: CircleProgressBar - - @Mock - private lateinit var imagesFeatured: TextView - - @Mock - private lateinit var tvQualityImages: TextView - - @Mock - private lateinit var imagesRevertLimitText: TextView - - @Mock - private lateinit var imageByWikiText: TextView - - @Mock - private lateinit var imageRevertedText: TextView - - @Mock - private lateinit var imageUploadedText: TextView - - @Mock - private lateinit var progressBar: ProgressBar - @Mock private lateinit var sessionManager: SessionManager @Mock private lateinit var parentView: ViewGroup + @Mock + private lateinit var account: Account + @Before fun setUp() { MockitoAnnotations.openMocks(this) + + fragment = AchievementsFragment() + Whitebox.setInternalState(fragment, "sessionManager", sessionManager) + Mockito.`when`(sessionManager.userName).thenReturn("Test") + Mockito.`when`(sessionManager.currentAccount).thenReturn(account) + context = ApplicationProvider.getApplicationContext() menuItem = RoboMenuItem(context) AppAdapter.set(TestAppAdapter()) val activity = Robolectric.buildActivity(ProfileActivity::class.java).create().get() - fragment = AchievementsFragment() val fragmentManager: FragmentManager = activity.supportFragmentManager val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction() fragmentTransaction.add(fragment, null) fragmentTransaction.commitNowAllowingStateLoss() layoutInflater = LayoutInflater.from(activity) - view = LayoutInflater.from(activity) - .inflate(R.layout.fragment_achievements, null) as View + view = fragment.onCreateView(layoutInflater, activity.findViewById(R.id.container), null)!! achievements = Achievements(0, 0, 0, 0, 0, 0, 0) - - Whitebox.setInternalState(fragment, "thanksReceived", thanksReceived) - Whitebox.setInternalState( - fragment, - "imagesUsedByWikiProgressBar", - imagesUsedByWikiProgressBar - ) - Whitebox.setInternalState( - fragment, - "imagesUsedByWikiProgressBar", - imagesUsedByWikiProgressBar - ) - Whitebox.setInternalState(fragment, "imagesFeatured", imagesFeatured) - Whitebox.setInternalState(fragment, "tvQualityImages", tvQualityImages) - Whitebox.setInternalState(fragment, "levelNumber", levelNumber) - Whitebox.setInternalState(fragment, "imageView", imageView) - Whitebox.setInternalState(fragment, "badgeText", badgeText) - Whitebox.setInternalState(fragment, "imagesUploadedProgressbar", imagesUploadedProgressbar) - Whitebox.setInternalState(fragment, "imageRevertsProgressbar", imageRevertsProgressbar) - Whitebox.setInternalState( - fragment, - "imagesUsedByWikiProgressBar", - imagesUsedByWikiProgressBar - ) - Whitebox.setInternalState(fragment, "imageView", imageView) - Whitebox.setInternalState(fragment, "imageByWikiText", imageByWikiText) - Whitebox.setInternalState(fragment, "imageRevertedText", imageRevertedText) - Whitebox.setInternalState(fragment, "imageUploadedText", imageUploadedText) - Whitebox.setInternalState(fragment, "imageView", imageView) - Whitebox.setInternalState(fragment, "progressBar", progressBar) - Whitebox.setInternalState(fragment, "imagesRevertLimitText", imagesRevertLimitText) - Whitebox.setInternalState(fragment, "item", menuItem) - Whitebox.setInternalState(fragment, "sessionManager", sessionManager) - Whitebox.setInternalState(fragment, "mView", parentView) - - Mockito.`when`(sessionManager.userName).thenReturn("Test") - } @Test @@ -354,18 +283,20 @@ class AchievementsFragmentUnitTests { @Test @Throws(Exception::class) fun testMenuVisibilityOverrideNotVisible() { + Shadows.shadowOf(Looper.getMainLooper()).idle() val method: Method = AchievementsFragment::class.java.getDeclaredMethod( "setMenuVisibility", Boolean::class.java ) method.isAccessible = true method.invoke(fragment, false) - Assert.assertNull(ShadowToast.getLatestToast()) + assertToast() } @Test @Throws(Exception::class) fun testMenuVisibilityOverrideVisibleWithContext() { + Shadows.shadowOf(Looper.getMainLooper()).idle() Mockito.`when`(parentView.context).thenReturn(context) val method: Method = AchievementsFragment::class.java.getDeclaredMethod( "setMenuVisibility", @@ -373,14 +304,19 @@ class AchievementsFragmentUnitTests { ) method.isAccessible = true method.invoke(fragment, true) - if(ConfigUtils.isBetaFlavour) { + assertToast() + } + + private fun assertToast() { + if (ConfigUtils.isBetaFlavour) { Assert.assertEquals( ShadowToast.getTextOfLatestToast().toString(), context.getString(R.string.achievements_unavailable_beta) ) } else { - Assert.assertNull( - ShadowToast.getTextOfLatestToast() + Assert.assertEquals( + context.getString(R.string.user_not_logged_in), + ShadowToast.getTextOfLatestToast().toString() ) } }