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

Add Picasso#rememberPainter extension function under new :picasso-compose module #2295

Merged
merged 1 commit into from
May 25, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
'targetSdk': 31,
'sourceCompatibility': JavaVersion.VERSION_1_8,
'targetCompatibility': JavaVersion.VERSION_1_8,
'kotlin': '1.5.21',
'kotlin': '1.6.10',
'okhttp': '4.9.3',
'okio': '3.0.0',
]
Expand All @@ -28,6 +28,9 @@ buildscript {
truth: 'com.google.truth:truth:1.1.3',
robolectric: 'org.robolectric:robolectric:4.6.1',
mockito: 'org.mockito:mockito-core:3.0.0',
drawablePainter: 'com.google.accompanist:accompanist-drawablepainter:0.23.1',
composeUi: 'androidx.compose.ui:ui:1.1.1',
foundation: 'androidx.compose.foundation:foundation:1.1.1'
]

ext.isCi = "true" == System.getenv('CI')
Expand Down
16 changes: 16 additions & 0 deletions picasso-compose/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Picasso Compose Ui
====================================

A [Painter] which wraps a [RequestCreator]

Usage
-----

Create a `Painter` using the rememberPainter extension on a Picasso instance.

```kotlin
val picasso = Picasso.Builder(context).build()
val painter = picasso.rememberPainter(key = url) {
it.load(url).placeholder(placeholderDrawable).error(errorDrawable)
}
```
4 changes: 4 additions & 0 deletions picasso-compose/api/picasso-compose.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public final class com/squareup/picasso3/compose/PicassoPainterKt {
public static final fun rememberPainter (Lcom/squareup/picasso3/Picasso;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Landroidx/compose/ui/graphics/painter/Painter;
}

40 changes: 40 additions & 0 deletions picasso-compose/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
apply plugin: 'com.android.library'
apply plugin: 'org.jetbrains.kotlin.android'
apply plugin: 'com.vanniktech.maven.publish'

android {
compileSdkVersion versions.compileSdk

defaultConfig {
minSdkVersion versions.minSdk
}

buildFeatures {
compose true
}

composeOptions {
kotlinCompilerExtensionVersion "1.1.1"
}

compileOptions {
sourceCompatibility versions.sourceCompatibility
targetCompatibility versions.targetCompatibility
}

lintOptions {
textOutput 'stdout'
textReport true
lintConfig rootProject.file('lint.xml')
}
}

dependencies {
api project(':picasso')

implementation deps.drawablePainter
implementation deps.composeUi
implementation deps.foundation

compileOnly deps.androidxAnnotations
}
4 changes: 4 additions & 0 deletions picasso-compose/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
POM_ARTIFACT_ID=picasso-compose
POM_NAME=Picasso Compose
POM_DESCRIPTION=Compose UI support for Picasso.
POM_PACKAGING=aar
1 change: 1 addition & 0 deletions picasso-compose/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest package="com.squareup.picasso3.compose" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright (C) 2022 Square, Inc.
*
* 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 com.squareup.picasso3.compose

import android.graphics.drawable.Drawable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.RememberObserver
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.DefaultAlpha
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.painter.Painter
import com.google.accompanist.drawablepainter.DrawablePainter
import com.squareup.picasso3.DrawableTarget
import com.squareup.picasso3.Picasso
import com.squareup.picasso3.Picasso.LoadedFrom
import com.squareup.picasso3.RequestCreator

@Composable
fun Picasso.rememberPainter(
key: Any? = null,
onError: ((Exception) -> Unit)? = null,
request: (Picasso) -> RequestCreator,
): Painter {
return remember(key) { PicassoPainter(this, request, onError) }
}

internal class PicassoPainter(
private val picasso: Picasso,
private val request: (Picasso) -> RequestCreator,
private val onError: ((Exception) -> Unit)? = null
) : Painter(), RememberObserver, DrawableTarget {

private var painter: Painter by mutableStateOf(EmptyPainter)
private var alpha: Float by mutableStateOf(DefaultAlpha)
private var colorFilter: ColorFilter? by mutableStateOf(null)

override val intrinsicSize: Size
get() = painter.intrinsicSize

override fun applyAlpha(alpha: Float): Boolean {
this.alpha = alpha
return true
}

override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {
this.colorFilter = colorFilter
return true
}

override fun DrawScope.onDraw() {
with(painter) {
draw(size, alpha, colorFilter)
}
}

override fun onRemembered() {
request.invoke(picasso).into(this)
}

override fun onAbandoned() {
(painter as? RememberObserver)?.onAbandoned()
painter = EmptyPainter
picasso.cancelRequest(this)
}

override fun onForgotten() {
(painter as? RememberObserver)?.onForgotten()
painter = EmptyPainter
picasso.cancelRequest(this)
}

override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
placeHolderDrawable?.let(::setPainter)
}

override fun onDrawableLoaded(drawable: Drawable, from: LoadedFrom) {
setPainter(drawable)
}

override fun onDrawableFailed(e: Exception, errorDrawable: Drawable?) {
onError?.invoke(e)
errorDrawable?.let(::setPainter)
}

private fun setPainter(drawable: Drawable) {
(painter as? RememberObserver)?.onForgotten()
painter = DrawablePainter(drawable).apply(DrawablePainter::onRemembered)
}
}

private object EmptyPainter : Painter() {
override val intrinsicSize = Size.Zero
override fun DrawScope.onDraw() = Unit
}
13 changes: 13 additions & 0 deletions picasso-sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ android {
applicationId 'com.example.picasso'
}

buildFeatures {
compose true
}

composeOptions {
kotlinCompilerExtensionVersion "1.1.1"
}

compileOptions {
sourceCompatibility versions.sourceCompatibility
targetCompatibility versions.targetCompatibility
Expand All @@ -32,6 +40,11 @@ dependencies {
implementation deps.androidxFragment
implementation deps.androidxStartup

implementation deps.drawablePainter
implementation deps.composeUi
implementation deps.foundation

implementation project(':picasso')
implementation project(':picasso-stats')
implementation project(':picasso-compose')
}
1 change: 1 addition & 0 deletions picasso-sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
</intent-filter>
</activity>

<activity android:name=".SampleComposeActivity"/>
<activity android:name=".SampleContactsActivity"/>
<activity android:name=".SampleGalleryActivity"/>
<activity android:name=".SampleListDetailActivity"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ internal class PicassoSampleAdapter(context: Context?) : BaseAdapter() {
private val activityClass: Class<out Activity>?
) {
GRID_VIEW("Image Grid View", SampleGridViewActivity::class.java),
COMPOSE_UI("Compose UI", SampleComposeActivity::class.java),
GALLERY("Load from Gallery", SampleGalleryActivity::class.java),
CONTACTS("Contact Photos", SampleContactsActivity::class.java),
LIST_DETAIL("List / Detail View", SampleListDetailActivity::class.java),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2022 Square, Inc.
*
* 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 com.example.picasso

import android.os.Bundle
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.GridCells.Adaptive
import androidx.compose.foundation.lazy.LazyVerticalGrid
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale.Companion.Crop
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.dp
import com.squareup.picasso3.Picasso
import com.squareup.picasso3.compose.rememberPainter

class SampleComposeActivity : PicassoSampleActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val composeView = ComposeView(this)

val urls = Data.URLS.toMutableList().shuffled() +
Data.URLS.toMutableList().shuffled() +
Data.URLS.toMutableList().shuffled()

composeView.setContent {
ImageGrid(urls = urls)
}

setContentView(composeView)
}
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ImageGrid(
modifier: Modifier = Modifier,
urls: List<String>,
picasso: Picasso = PicassoInitializer.get()
) {
LazyVerticalGrid(
cells = Adaptive(150.dp),
modifier = modifier,
) {
items(urls.size) {
val url = urls[it]
Image(
painter = picasso.rememberPainter(key = url) {
it.load(url).placeholder(R.drawable.placeholder).error(R.drawable.error)
},
contentDescription = null,
contentScale = Crop,
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
)
}
}
}
8 changes: 8 additions & 0 deletions picasso/api/picasso.api
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ public class com/squareup/picasso3/Callback$EmptyCallback : com/squareup/picasso
public fun onSuccess ()V
}

public abstract interface class com/squareup/picasso3/DrawableTarget {
public abstract fun onDrawableFailed (Ljava/lang/Exception;Landroid/graphics/drawable/Drawable;)V
public abstract fun onDrawableLoaded (Landroid/graphics/drawable/Drawable;Lcom/squareup/picasso3/Picasso$LoadedFrom;)V
public abstract fun onPrepareLoad (Landroid/graphics/drawable/Drawable;)V
}

public abstract interface class com/squareup/picasso3/EventListener : java/io/Closeable {
public abstract fun bitmapDecoded (Landroid/graphics/Bitmap;)V
public abstract fun bitmapTransformed (Landroid/graphics/Bitmap;)V
Expand Down Expand Up @@ -72,6 +78,7 @@ public final class com/squareup/picasso3/Picasso : androidx/lifecycle/LifecycleO
public final fun cancelRequest (Landroid/widget/ImageView;)V
public final fun cancelRequest (Landroid/widget/RemoteViews;I)V
public final fun cancelRequest (Lcom/squareup/picasso3/BitmapTarget;)V
public final fun cancelRequest (Lcom/squareup/picasso3/DrawableTarget;)V
public final fun cancelTag (Ljava/lang/Object;)V
public final fun evictAll ()V
public final fun getIndicatorsEnabled ()Z
Expand Down Expand Up @@ -272,6 +279,7 @@ public final class com/squareup/picasso3/RequestCreator {
public final fun into (Landroid/widget/RemoteViews;I[I)V
public final fun into (Landroid/widget/RemoteViews;I[ILcom/squareup/picasso3/Callback;)V
public final fun into (Lcom/squareup/picasso3/BitmapTarget;)V
public final fun into (Lcom/squareup/picasso3/DrawableTarget;)V
public static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/ImageView;Lcom/squareup/picasso3/Callback;ILjava/lang/Object;)V
public static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/RemoteViews;IILandroid/app/Notification;Ljava/lang/String;Lcom/squareup/picasso3/Callback;ILjava/lang/Object;)V
public static synthetic fun into$default (Lcom/squareup/picasso3/RequestCreator;Landroid/widget/RemoteViews;IILcom/squareup/picasso3/Callback;ILjava/lang/Object;)V
Expand Down
Loading