Skip to content

Commit 01cfad9

Browse files
committed
Add Picasso#rememberPainter extension function under new :picasso-compose module
1 parent f61200d commit 01cfad9

File tree

23 files changed

+694
-38
lines changed

23 files changed

+694
-38
lines changed

build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ buildscript {
55
'targetSdk': 31,
66
'sourceCompatibility': JavaVersion.VERSION_1_8,
77
'targetCompatibility': JavaVersion.VERSION_1_8,
8-
'kotlin': '1.5.21',
8+
'kotlin': '1.6.10',
99
'okhttp': '4.9.3',
1010
'okio': '3.0.0',
1111
]
@@ -28,6 +28,9 @@ buildscript {
2828
truth: 'com.google.truth:truth:1.1.3',
2929
robolectric: 'org.robolectric:robolectric:4.6.1',
3030
mockito: 'org.mockito:mockito-core:3.0.0',
31+
drawablePainter: 'com.google.accompanist:accompanist-drawablepainter:0.23.1',
32+
composeUi: 'androidx.compose.ui:ui:1.1.1',
33+
foundation: 'androidx.compose.foundation:foundation:1.1.1'
3134
]
3235

3336
ext.isCi = "true" == System.getenv('CI')

picasso-compose/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Picasso Compose Ui
2+
====================================
3+
4+
A [Painter] which wraps a [RequestCreator]
5+
6+
Usage
7+
-----
8+
9+
Create a `Painter` using the rememberPainter extension on a Picasso instance.
10+
11+
```kotlin
12+
val picasso = Picasso.Builder(context).build()
13+
val painter = picasso.rememberPainter(key = url) {
14+
it.load(url).placeholder(placeholderDrawable).error(errorDrawable)
15+
}
16+
```
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public final class com/squareup/picasso3/compose/PicassoPainterKt {
2+
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;
3+
}
4+

picasso-compose/build.gradle

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
apply plugin: 'com.android.library'
2+
apply plugin: 'org.jetbrains.kotlin.android'
3+
apply plugin: 'com.vanniktech.maven.publish'
4+
5+
android {
6+
compileSdkVersion versions.compileSdk
7+
8+
defaultConfig {
9+
minSdkVersion versions.minSdk
10+
}
11+
12+
buildFeatures {
13+
compose true
14+
}
15+
16+
composeOptions {
17+
kotlinCompilerExtensionVersion "1.1.1"
18+
}
19+
20+
compileOptions {
21+
sourceCompatibility versions.sourceCompatibility
22+
targetCompatibility versions.targetCompatibility
23+
}
24+
25+
lintOptions {
26+
textOutput 'stdout'
27+
textReport true
28+
lintConfig rootProject.file('lint.xml')
29+
}
30+
}
31+
32+
dependencies {
33+
api project(':picasso')
34+
35+
implementation deps.drawablePainter
36+
implementation deps.composeUi
37+
implementation deps.foundation
38+
39+
compileOnly deps.androidxAnnotations
40+
}

picasso-compose/gradle.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
POM_ARTIFACT_ID=picasso-compose
2+
POM_NAME=Picasso Compose
3+
POM_DESCRIPTION=Compose UI support for Picasso.
4+
POM_PACKAGING=aar
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<manifest package="com.squareup.picasso3.compose" />
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (C) 2022 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.squareup.picasso3.compose
17+
18+
import android.graphics.drawable.Drawable
19+
import androidx.compose.runtime.Composable
20+
import androidx.compose.runtime.RememberObserver
21+
import androidx.compose.runtime.getValue
22+
import androidx.compose.runtime.mutableStateOf
23+
import androidx.compose.runtime.remember
24+
import androidx.compose.runtime.setValue
25+
import androidx.compose.ui.geometry.Size
26+
import androidx.compose.ui.graphics.ColorFilter
27+
import androidx.compose.ui.graphics.DefaultAlpha
28+
import androidx.compose.ui.graphics.drawscope.DrawScope
29+
import androidx.compose.ui.graphics.painter.Painter
30+
import com.google.accompanist.drawablepainter.DrawablePainter
31+
import com.squareup.picasso3.DrawableTarget
32+
import com.squareup.picasso3.Picasso
33+
import com.squareup.picasso3.Picasso.LoadedFrom
34+
import com.squareup.picasso3.RequestCreator
35+
36+
@Composable
37+
fun Picasso.rememberPainter(
38+
key: Any? = null,
39+
onError: ((Exception) -> Unit)? = null,
40+
request: (Picasso) -> RequestCreator,
41+
): Painter {
42+
return remember(key) { PicassoPainter(this, request, onError) }
43+
}
44+
45+
internal class PicassoPainter(
46+
private val picasso: Picasso,
47+
private val request: (Picasso) -> RequestCreator,
48+
private val onError: ((Exception) -> Unit)? = null
49+
) : Painter(), RememberObserver, DrawableTarget {
50+
51+
private var painter: Painter by mutableStateOf(EmptyPainter)
52+
private var alpha: Float by mutableStateOf(DefaultAlpha)
53+
private var colorFilter: ColorFilter? by mutableStateOf(null)
54+
55+
override val intrinsicSize: Size
56+
get() = painter.intrinsicSize
57+
58+
override fun applyAlpha(alpha: Float): Boolean {
59+
this.alpha = alpha
60+
return true
61+
}
62+
63+
override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {
64+
this.colorFilter = colorFilter
65+
return true
66+
}
67+
68+
override fun DrawScope.onDraw() {
69+
with(painter) {
70+
draw(size, alpha, colorFilter)
71+
}
72+
}
73+
74+
override fun onRemembered() {
75+
request.invoke(picasso).into(this)
76+
}
77+
78+
override fun onAbandoned() {
79+
(painter as? RememberObserver)?.onAbandoned()
80+
painter = EmptyPainter
81+
picasso.cancelRequest(this)
82+
}
83+
84+
override fun onForgotten() {
85+
(painter as? RememberObserver)?.onForgotten()
86+
painter = EmptyPainter
87+
picasso.cancelRequest(this)
88+
}
89+
90+
override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
91+
placeHolderDrawable?.let(::setPainter)
92+
}
93+
94+
override fun onDrawableLoaded(drawable: Drawable, from: LoadedFrom) {
95+
setPainter(drawable)
96+
}
97+
98+
override fun onDrawableFailed(e: Exception, errorDrawable: Drawable?) {
99+
onError?.invoke(e)
100+
errorDrawable?.let(::setPainter)
101+
}
102+
103+
private fun setPainter(drawable: Drawable) {
104+
(painter as? RememberObserver)?.onForgotten()
105+
painter = DrawablePainter(drawable).apply(DrawablePainter::onRemembered)
106+
}
107+
}
108+
109+
private object EmptyPainter : Painter() {
110+
override val intrinsicSize = Size.Zero
111+
override fun DrawScope.onDraw() = Unit
112+
}

picasso-sample/build.gradle

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ android {
1010
applicationId 'com.example.picasso'
1111
}
1212

13+
buildFeatures {
14+
compose true
15+
}
16+
17+
composeOptions {
18+
kotlinCompilerExtensionVersion "1.1.1"
19+
}
20+
1321
compileOptions {
1422
sourceCompatibility versions.sourceCompatibility
1523
targetCompatibility versions.targetCompatibility
@@ -32,6 +40,11 @@ dependencies {
3240
implementation deps.androidxFragment
3341
implementation deps.androidxStartup
3442

43+
implementation deps.drawablePainter
44+
implementation deps.composeUi
45+
implementation deps.foundation
46+
3547
implementation project(':picasso')
3648
implementation project(':picasso-stats')
49+
implementation project(':picasso-compose')
3750
}

picasso-sample/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
</intent-filter>
3535
</activity>
3636

37+
<activity android:name=".SampleComposeActivity"/>
3738
<activity android:name=".SampleContactsActivity"/>
3839
<activity android:name=".SampleGalleryActivity"/>
3940
<activity android:name=".SampleListDetailActivity"/>

picasso-sample/src/main/java/com/example/picasso/PicassoSampleAdapter.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ internal class PicassoSampleAdapter(context: Context?) : BaseAdapter() {
3838
private val activityClass: Class<out Activity>?
3939
) {
4040
GRID_VIEW("Image Grid View", SampleGridViewActivity::class.java),
41+
COMPOSE_UI("Compose UI", SampleComposeActivity::class.java),
4142
GALLERY("Load from Gallery", SampleGalleryActivity::class.java),
4243
CONTACTS("Contact Photos", SampleContactsActivity::class.java),
4344
LIST_DETAIL("List / Detail View", SampleListDetailActivity::class.java),

0 commit comments

Comments
 (0)