Image.kt
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.glance
import android.graphics.Bitmap
import android.graphics.drawable.Icon
import android.os.Build
import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.compose.runtime.Composable
import androidx.glance.layout.ContentScale
import androidx.glance.semantics.contentDescription
import androidx.glance.semantics.semantics
import androidx.glance.unit.ColorProvider
/**
* Interface representing an Image source which can be used with a Glance [Image] element.
*/
interface ImageProvider
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
/** @suppress */
class AndroidResourceImageProvider(@DrawableRes val resId: Int) : ImageProvider {
override fun toString() = "AndroidResourceImageProvider(resId=$resId)"
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
/** @suppress */
class BitmapImageProvider(val bitmap: Bitmap) : ImageProvider {
override fun toString() =
"BitmapImageProvider(bitmap=Bitmap(${bitmap.width}px x ${bitmap.height}px))"
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
/** @suppress */
class IconImageProvider(val icon: Icon) : ImageProvider {
override fun toString() = "IconImageProvider(icon=$icon)"
}
/**
* Image resource from an Android Drawable resource.
*
* @param resId The resource ID of the Drawable resource to be used.
*/
fun ImageProvider(@DrawableRes resId: Int): ImageProvider =
AndroidResourceImageProvider(resId)
/**
* Image resource from a bitmap.
*
* @param bitmap The bitmap to be displayed.
*/
fun ImageProvider(bitmap: Bitmap): ImageProvider = BitmapImageProvider(bitmap)
/**
* Image resource from an icon.
*
* @param icon The icon to be displayed.
*/
@RequiresApi(Build.VERSION_CODES.M)
fun ImageProvider(icon: Icon): ImageProvider = IconImageProvider(icon)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
/** @suppress */
interface ColorFilterParams
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
/** @suppress */
class TintColorFilterParams(val colorProvider: ColorProvider) : ColorFilterParams {
override fun toString() =
"TintColorFilterParams(colorProvider=$colorProvider))"
}
/**
* Effects used to modify the color of an image.
*/
class ColorFilter internal constructor(internal val colorFilterParams: ColorFilterParams) {
companion object {
/**
* Set a tinting option for the image using the platform-specific default blending mode.
*
* @param colorProvider Provider used to get the color for blending the source content.
*/
fun tint(colorProvider: ColorProvider): ColorFilter =
ColorFilter(TintColorFilterParams(colorProvider))
}
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
/** @suppress */
class EmittableImage : Emittable {
override var modifier: GlanceModifier = GlanceModifier
var provider: ImageProvider? = null
var colorFilterParams: ColorFilterParams? = null
var contentScale: ContentScale = ContentScale.Fit
override fun copy(): Emittable = EmittableImage().also {
it.modifier = modifier
it.provider = provider
it.colorFilterParams = colorFilterParams
it.contentScale = contentScale
}
override fun toString(): String = "EmittableImage(" +
"modifier=$modifier, " +
"provider=$provider, " +
"colorFilterParams=$colorFilterParams, " +
"contentScale=$contentScale" +
")"
}
/**
* A composable which lays out and draws the image specified in [provider]. This will attempt to lay
* out the image using the intrinsic width and height of the provided image, but this can be
* overridden by using a modifier to set the width or height of this element.
*
* @param provider The image provider to use to draw the image
* @param contentDescription text used by accessibility services to describe what this image
* represents. This should always be provided unless this image is used for decorative purposes,
* and does not represent a meaningful action that a user can take. This text should be
* localized.
* @param modifier Modifier used to adjust the layout algorithm or draw decoration content.
* @param contentScale How to lay the image out with respect to its bounds, if the bounds are
* smaller than the image.
* @param colorFilter The effects to use to modify the color of an image.
*/
@Composable
fun Image(
provider: ImageProvider,
contentDescription: String?,
modifier: GlanceModifier = GlanceModifier,
contentScale: ContentScale = ContentScale.Fit,
colorFilter: ColorFilter? = null
) {
val finalModifier = if (contentDescription != null) {
modifier.semantics {
this.contentDescription = contentDescription
}
} else {
modifier
}
GlanceNode(
factory = ::EmittableImage,
update = {
this.set(provider) { this.provider = it }
this.set(finalModifier) { this.modifier = it }
this.set(contentScale) { this.contentScale = it }
this.set(colorFilter) { this.colorFilterParams = it?.colorFilterParams }
}
)
}