Skip to content

Commit 3d525d4

Browse files
authored
Removed butterknife from contributions list fragment (commons-app#5396)
* Removed butterknife from contributions list fragment and overhauled its test * Suggested fix from stack overflow to remove duplicate class error during build
1 parent 8b05492 commit 3d525d4

File tree

5 files changed

+127
-185
lines changed

5 files changed

+127
-185
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,7 @@ app/src/main/jniLibs
4343
#https://docs.opencv.org/3.3.0/
4444
/libraries/opencv/javadoc/
4545
captures/*
46+
47+
# Test and other output
48+
app/jacoco.exec
49+
app/CommonsContributions

app/build.gradle

+19-6
Original file line numberDiff line numberDiff line change
@@ -75,30 +75,32 @@ dependencies {
7575
kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
7676
annotationProcessor "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
7777

78-
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$KOTLIN_VERSION"
7978
implementation "org.jetbrains.kotlin:kotlin-reflect:$KOTLIN_VERSION"
8079

8180
//Mocking
8281
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'
8382
testImplementation 'org.mockito:mockito-inline:5.2.0'
84-
testImplementation 'org.mockito:mockito-core:5.5.0'
83+
testImplementation 'org.mockito:mockito-core:5.6.0'
8584
testImplementation "org.powermock:powermock-module-junit4:2.0.9"
8685
testImplementation "org.powermock:powermock-api-mockito2:2.0.9"
8786

8887
// Unit testing
8988
testImplementation 'junit:junit:4.13.2'
90-
testImplementation 'org.robolectric:robolectric:4.10.3'
89+
testImplementation 'org.robolectric:robolectric:4.11.1'
9190
testImplementation 'androidx.test:core:1.5.0'
91+
testImplementation "androidx.test:runner:1.5.2"
92+
testImplementation 'androidx.test.ext:junit:1.1.5'
93+
testImplementation "androidx.test:rules:1.5.0"
9294
testImplementation "com.squareup.okhttp3:mockwebserver:$OKHTTP_VERSION"
9395
testImplementation "com.jraska.livedata:testing-ktx:1.1.2"
9496
testImplementation "androidx.arch.core:core-testing:2.2.0"
9597
testImplementation "org.junit.jupiter:junit-jupiter-api:5.10.0"
9698
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.10.0"
9799
testImplementation 'com.facebook.soloader:soloader:0.10.5'
98100
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3"
101+
debugImplementation("androidx.fragment:fragment-testing:1.6.2")
99102

100103
// Android testing
101-
androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$KOTLIN_VERSION"
102104
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0-alpha04'
103105
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'
104106
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.0-alpha04'
@@ -158,6 +160,15 @@ dependencies {
158160
kaptAndroidTest "androidx.databinding:databinding-compiler:8.0.2"
159161

160162
implementation("io.github.coordinates2country:coordinates2country-android:1.3") { exclude group: 'com.google.android', module: 'android' }
163+
164+
constraints {
165+
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") {
166+
because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib")
167+
}
168+
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") {
169+
because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib")
170+
}
171+
}
161172
}
162173

163174
task disableAnimations(type: Exec) {
@@ -206,8 +217,10 @@ android {
206217
testOptions {
207218
animationsDisabled true
208219

209-
unitTests.returnDefaultValues = true
210-
unitTests.includeAndroidResources = true
220+
unitTests {
221+
returnDefaultValues = true
222+
includeAndroidResources = true
223+
}
211224

212225
unitTests.all {
213226
jvmArgs '-noverify'

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java

+54-63
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import androidx.activity.result.contract.ActivityResultContracts;
2525
import androidx.annotation.NonNull;
2626
import androidx.annotation.Nullable;
27+
import androidx.annotation.VisibleForTesting;
2728
import androidx.appcompat.widget.AppCompatTextView;
2829
import androidx.fragment.app.FragmentManager;
2930
import androidx.recyclerview.widget.GridLayoutManager;
@@ -32,15 +33,13 @@
3233
import androidx.recyclerview.widget.RecyclerView.ItemAnimator;
3334
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
3435
import androidx.recyclerview.widget.SimpleItemAnimator;
35-
import butterknife.BindView;
36-
import butterknife.ButterKnife;
37-
import butterknife.OnClick;
3836
import com.google.android.material.floatingactionbutton.FloatingActionButton;
3937
import fr.free.nrw.commons.CommonsApplication;
4038
import fr.free.nrw.commons.Media;
4139
import fr.free.nrw.commons.R;
4240
import fr.free.nrw.commons.Utils;
4341
import fr.free.nrw.commons.auth.SessionManager;
42+
import fr.free.nrw.commons.databinding.FragmentContributionsListBinding;
4443
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
4544
import fr.free.nrw.commons.media.MediaClient;
4645
import fr.free.nrw.commons.profile.ProfileActivity;
@@ -66,61 +65,43 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
6665

6766
private static final String RV_STATE = "rv_scroll_state";
6867

69-
@BindView(R.id.contributionsList)
70-
RecyclerView rvContributionsList;
71-
@BindView(R.id.loadingContributionsProgressBar)
72-
ProgressBar progressBar;
73-
@BindView(R.id.fab_plus)
74-
FloatingActionButton fabPlus;
75-
@BindView(R.id.fab_camera)
76-
FloatingActionButton fabCamera;
77-
@BindView(R.id.fab_gallery)
78-
FloatingActionButton fabGallery;
79-
@BindView(R.id.noContributionsYet)
80-
TextView noContributionsYet;
81-
@BindView(R.id.fab_layout)
82-
LinearLayout fab_layout;
83-
@BindView(R.id.fab_custom_gallery)
84-
FloatingActionButton fabCustomGallery;
85-
8668
@Inject
8769
SystemThemeUtils systemThemeUtils;
88-
@BindView(R.id.tv_contributions_of_user)
89-
AppCompatTextView tvContributionsOfUser;
90-
9170
@Inject
9271
ContributionController controller;
9372
@Inject
9473
MediaClient mediaClient;
95-
9674
@Named(NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE)
9775
@Inject
9876
WikiSite languageWikipediaSite;
99-
10077
@Inject
10178
ContributionsListPresenter contributionsListPresenter;
102-
10379
@Inject
10480
SessionManager sessionManager;
10581

82+
private FragmentContributionsListBinding binding;
10683
private Animation fab_close;
10784
private Animation fab_open;
10885
private Animation rotate_forward;
10986
private Animation rotate_backward;
110-
111-
11287
private boolean isFabOpen;
11388

114-
private ContributionsListAdapter adapter;
89+
@VisibleForTesting
90+
protected RecyclerView rvContributionsList;
91+
92+
@VisibleForTesting
93+
protected ContributionsListAdapter adapter;
11594

11695
@Nullable
117-
private Callback callback;
96+
@VisibleForTesting
97+
protected Callback callback;
11898

11999
private final int SPAN_COUNT_LANDSCAPE = 3;
120100
private final int SPAN_COUNT_PORTRAIT = 1;
121101

122102
private int contributionsSize;
123-
String userName;
103+
private String userName;
104+
124105
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
125106
@Override
126107
public void onActivityResult(Map<String, Boolean> result) {
@@ -162,21 +143,32 @@ public void onCreate(
162143
public View onCreateView(
163144
final LayoutInflater inflater, @Nullable final ViewGroup container,
164145
@Nullable final Bundle savedInstanceState) {
165-
final View view = inflater.inflate(R.layout.fragment_contributions_list, container, false);
166-
ButterKnife.bind(this, view);
146+
binding = FragmentContributionsListBinding.inflate(
147+
inflater, container, false
148+
);
149+
rvContributionsList = binding.contributionsList;
150+
167151
contributionsListPresenter.onAttachView(this);
152+
binding.fabCustomGallery.setOnClickListener(v -> launchCustomSelector());
168153

169154
if (Objects.equals(sessionManager.getUserName(), userName)) {
170-
tvContributionsOfUser.setVisibility(GONE);
171-
fab_layout.setVisibility(VISIBLE);
155+
binding.tvContributionsOfUser.setVisibility(GONE);
156+
binding.fabLayout.setVisibility(VISIBLE);
172157
} else {
173-
tvContributionsOfUser.setVisibility(VISIBLE);
174-
tvContributionsOfUser.setText(getString(R.string.contributions_of_user, userName));
175-
fab_layout.setVisibility(GONE);
158+
binding.tvContributionsOfUser.setVisibility(VISIBLE);
159+
binding.tvContributionsOfUser.setText(getString(R.string.contributions_of_user, userName));
160+
binding.fabLayout.setVisibility(GONE);
176161
}
177162

178163
initAdapter();
179-
return view;
164+
165+
return binding.getRoot();
166+
}
167+
168+
@Override
169+
public void onDestroyView() {
170+
binding = null;
171+
super.onDestroyView();
180172
}
181173

182174
@Override
@@ -309,7 +301,7 @@ private int getSpanCount(final int orientation) {
309301
public void onConfigurationChanged(final Configuration newConfig) {
310302
super.onConfigurationChanged(newConfig);
311303
// check orientation
312-
fab_layout.setOrientation(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ?
304+
binding.fabLayout.setOrientation(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ?
313305
LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
314306
rvContributionsList
315307
.setLayoutManager(
@@ -324,12 +316,12 @@ private void initializeAnimations() {
324316
}
325317

326318
private void setListeners() {
327-
fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
328-
fabCamera.setOnClickListener(view -> {
319+
binding.fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
320+
binding.fabCamera.setOnClickListener(view -> {
329321
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher);
330322
animateFAB(isFabOpen);
331323
});
332-
fabGallery.setOnClickListener(view -> {
324+
binding.fabGallery.setOnClickListener(view -> {
333325
controller.initiateGalleryPick(getActivity(), true);
334326
animateFAB(isFabOpen);
335327
});
@@ -338,8 +330,7 @@ private void setListeners() {
338330
/**
339331
* Launch Custom Selector.
340332
*/
341-
@OnClick(R.id.fab_custom_gallery)
342-
void launchCustomSelector() {
333+
protected void launchCustomSelector() {
343334
controller.initiateCustomGalleryPickWithPermission(getActivity());
344335
animateFAB(isFabOpen);
345336
}
@@ -350,23 +341,23 @@ public void scrollToTop() {
350341

351342
private void animateFAB(final boolean isFabOpen) {
352343
this.isFabOpen = !isFabOpen;
353-
if (fabPlus.isShown()) {
344+
if (binding.fabPlus.isShown()) {
354345
if (isFabOpen) {
355-
fabPlus.startAnimation(rotate_backward);
356-
fabCamera.startAnimation(fab_close);
357-
fabGallery.startAnimation(fab_close);
358-
fabCustomGallery.startAnimation(fab_close);
359-
fabCamera.hide();
360-
fabGallery.hide();
361-
fabCustomGallery.hide();
346+
binding.fabPlus.startAnimation(rotate_backward);
347+
binding.fabCamera.startAnimation(fab_close);
348+
binding.fabGallery.startAnimation(fab_close);
349+
binding.fabCustomGallery.startAnimation(fab_close);
350+
binding.fabCamera.hide();
351+
binding.fabGallery.hide();
352+
binding.fabCustomGallery.hide();
362353
} else {
363-
fabPlus.startAnimation(rotate_forward);
364-
fabCamera.startAnimation(fab_open);
365-
fabGallery.startAnimation(fab_open);
366-
fabCustomGallery.startAnimation(fab_open);
367-
fabCamera.show();
368-
fabGallery.show();
369-
fabCustomGallery.show();
354+
binding.fabPlus.startAnimation(rotate_forward);
355+
binding.fabCamera.startAnimation(fab_open);
356+
binding.fabGallery.startAnimation(fab_open);
357+
binding.fabCustomGallery.startAnimation(fab_open);
358+
binding.fabCamera.show();
359+
binding.fabGallery.show();
360+
binding.fabCustomGallery.show();
370361
}
371362
this.isFabOpen = !isFabOpen;
372363
}
@@ -377,7 +368,7 @@ private void animateFAB(final boolean isFabOpen) {
377368
*/
378369
@Override
379370
public void showWelcomeTip(final boolean shouldShow) {
380-
noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE);
371+
binding.noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE);
381372
}
382373

383374
/**
@@ -387,12 +378,12 @@ public void showWelcomeTip(final boolean shouldShow) {
387378
*/
388379
@Override
389380
public void showProgress(final boolean shouldShow) {
390-
progressBar.setVisibility(shouldShow ? VISIBLE : GONE);
381+
binding.loadingContributionsProgressBar.setVisibility(shouldShow ? VISIBLE : GONE);
391382
}
392383

393384
@Override
394385
public void showNoContributionsUI(final boolean shouldShow) {
395-
noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE);
386+
binding.noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE);
396387
}
397388

398389
@Override

0 commit comments

Comments
 (0)