Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement equals/hashcode for RequestOptions and TransitionOptions #4917

Merged
merged 1 commit into from Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions integration/compose/build.gradle
Expand Up @@ -60,6 +60,7 @@ dependencies {
androidTestImplementation "androidx.test.espresso:espresso-core:$ANDROID_X_TEST_ESPRESSO_VERSION"
androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$ANDROID_X_TEST_ESPRESSO_VERSION"
androidTestImplementation "androidx.test.ext:junit:$ANDROID_X_TEST_JUNIT_VERSION"
androidTestImplementation "androidx.compose.material:material:$ANDROID_X_COMPOSE_VERSION"
}

apply from: "${rootProject.projectDir}/scripts/upload.gradle"
Expand Up @@ -5,22 +5,30 @@ package com.bumptech.glide.integration.compose
import android.content.Context
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.SemanticsPropertyKey
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.unit.dp
import androidx.test.core.app.ApplicationProvider
import com.bumptech.glide.Glide
import com.bumptech.glide.integration.ktx.InternalGlideApi
import com.bumptech.glide.integration.ktx.Size
import com.bumptech.glide.load.engine.executor.GlideIdlingResourceInit
import java.util.concurrent.atomic.AtomicReference
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
Expand All @@ -34,6 +42,11 @@ class GlideComposeTest {
GlideIdlingResourceInit.initGlide(composeRule)
}

@After
fun tearDown() {
Glide.tearDown()
}

@Test
fun glideImage_noModifierSize_resourceDrawable_displaysDrawable() {
val description = "test"
Expand Down Expand Up @@ -68,6 +81,40 @@ class GlideComposeTest {
.assert(expectDisplayedDrawableSize(expectedSize))
}

@Test
fun glideImage_withChangingModel_refreshes() {
val description = "test"

val firstDrawable: Drawable = context.getDrawable(android.R.drawable.star_big_off)!!
val secondDrawable: Drawable = context.getDrawable(android.R.drawable.star_big_on)!!

composeRule.setContent {
val model = remember { mutableStateOf(firstDrawable) }

fun swapModel() {
model.value = secondDrawable
}

Column {
TextButton(onClick = ::swapModel) {Text(text="Swap")}
GlideImage(
model = model.value,
modifier = Modifier.size(100.dp),
contentDescription = description
)
}
}

composeRule.waitForIdle()
composeRule.onNodeWithText("Swap").performClick()
composeRule.waitForIdle()

val fullsizeBitmap = (secondDrawable as BitmapDrawable).bitmap
composeRule
.onNodeWithContentDescription(description)
.assert(expectDisplayedDrawable(fullsizeBitmap) { (it as BitmapDrawable).bitmap })
}

@Test
fun glideImage_withSizeLargerThanImage_upscaleTransformSet_upscalesImage() {
val viewDimension = 300
Expand Down
Expand Up @@ -55,4 +55,18 @@ public static <TranscodeType> GenericTransitionOptions<TranscodeType> with(
@NonNull TransitionFactory<? super TranscodeType> transitionFactory) {
return new GenericTransitionOptions<TranscodeType>().transition(transitionFactory);
}

// Make sure that we're not equal to any other concrete implementation of TransitionOptions.
@Override
public boolean equals(Object o) {
return o instanceof GenericTransitionOptions && super.equals(o);
}

// Our class doesn't include any additional properties, so we don't need to modify hashcode, but
// keep it here as a reminder in case we add properties.
@SuppressWarnings("PMD.UselessOverridingMethod")
@Override
public int hashCode() {
return super.hashCode();
}
}
35 changes: 35 additions & 0 deletions library/src/main/java/com/bumptech/glide/RequestBuilder.java
Expand Up @@ -42,6 +42,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;

/**
Expand Down Expand Up @@ -80,6 +81,7 @@ public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBui
@Nullable private Float thumbSizeMultiplier;
private boolean isDefaultTransitionOptionsSet = true;
private boolean isModelSet;

private boolean isThumbnailBuilt;

// We only override the method to change the return type, not the functionality.
Expand Down Expand Up @@ -1251,4 +1253,37 @@ private Request obtainRequest(
transitionOptions.getTransitionFactory(),
callbackExecutor);
}

@Override
public boolean equals(Object o) {
if (o instanceof RequestBuilder<?>) {
RequestBuilder<?> that = (RequestBuilder<?>) o;
return super.equals(that)
&& Objects.equals(transcodeClass, that.transcodeClass)
&& transitionOptions.equals(that.transitionOptions)
&& Objects.equals(model, that.model)
&& Objects.equals(requestListeners, that.requestListeners)
&& Objects.equals(thumbnailBuilder, that.thumbnailBuilder)
&& Objects.equals(errorBuilder, that.errorBuilder)
&& Objects.equals(thumbSizeMultiplier, that.thumbSizeMultiplier)
&& isDefaultTransitionOptionsSet == that.isDefaultTransitionOptionsSet
&& isModelSet == that.isModelSet;
}
return false;
}

@Override
public int hashCode() {
int hashCode = super.hashCode();
hashCode = Util.hashCode(transcodeClass, hashCode);
hashCode = Util.hashCode(transitionOptions, hashCode);
hashCode = Util.hashCode(model, hashCode);
hashCode = Util.hashCode(requestListeners, hashCode);
hashCode = Util.hashCode(thumbnailBuilder, hashCode);
hashCode = Util.hashCode(errorBuilder, hashCode);
hashCode = Util.hashCode(thumbSizeMultiplier, hashCode);
hashCode = Util.hashCode(isDefaultTransitionOptionsSet, hashCode);
hashCode = Util.hashCode(isModelSet, hashCode);
return hashCode;
}
}
17 changes: 17 additions & 0 deletions library/src/main/java/com/bumptech/glide/TransitionOptions.java
Expand Up @@ -7,10 +7,13 @@
import com.bumptech.glide.request.transition.ViewPropertyAnimationFactory;
import com.bumptech.glide.request.transition.ViewPropertyTransition;
import com.bumptech.glide.util.Preconditions;
import com.bumptech.glide.util.Util;

/**
* A base class for setting a transition to use on a resource when a load completes.
*
* <p>Note: Implementations must implement equals/hashcode.
*
* @param <CHILD> The implementation of this class to return to chain methods.
* @param <TranscodeType> The type of resource that will be animated.
*/
Expand Down Expand Up @@ -97,4 +100,18 @@ final TransitionFactory<? super TranscodeType> getTransitionFactory() {
private CHILD self() {
return (CHILD) this;
}

@Override
public boolean equals(Object o) {
if (o instanceof TransitionOptions) {
TransitionOptions<?, ?> other = (TransitionOptions<?, ?>) o;
return Util.bothNullOrEqual(transitionFactory, other.transitionFactory);
}
return false;
}

@Override
public int hashCode() {
return transitionFactory != null ? transitionFactory.hashCode() : 0;
}
}
Expand Up @@ -125,4 +125,18 @@ public BitmapTransitionOptions transitionUsing(
public BitmapTransitionOptions crossFade(@NonNull DrawableCrossFadeFactory.Builder builder) {
return transitionUsing(builder.build());
}

// Make sure that we're not equal to any other concrete implementation of TransitionOptions.
@Override
public boolean equals(Object o) {
return o instanceof BitmapTransitionOptions && super.equals(o);
}

// Our class doesn't include any additional properties, so we don't need to modify hashcode, but
// keep it here as a reminder in case we add properties.
@SuppressWarnings("PMD.UselessOverridingMethod")
@Override
public int hashCode() {
return super.hashCode();
}
}
Expand Up @@ -105,4 +105,19 @@ public DrawableTransitionOptions crossFade(
public DrawableTransitionOptions crossFade(@NonNull DrawableCrossFadeFactory.Builder builder) {
return crossFade(builder.build());
}

// Make sure that we're not equal to any other concrete implementation of TransitionOptions.
@Override
public boolean equals(Object o) {
return o instanceof DrawableTransitionOptions && super.equals(o);
}

// Our class doesn't include any additional properties, so we don't need to modify hashcode, but
// keep it here as a reminder in case we add properties.
@SuppressWarnings("PMD.UselessOverridingMethod")
@Override
public int hashCode() {
return super.hashCode();
}
}

Expand Up @@ -279,4 +279,18 @@ public static RequestOptions noAnimation() {
}
return noAnimationOptions;
}

// Make sure that we're not equal to any other concrete implementation of RequestOptions.
@Override
public boolean equals(Object o) {
return o instanceof RequestOptions && super.equals(o);
}

// Our class doesn't include any additional properties, so we don't need to modify hashcode, but
// keep it here as a reminder in case we add properties.
@SuppressWarnings("PMD.UselessOverridingMethod")
@Override
public int hashCode() {
return super.hashCode();
}
}