ganfra
2 years ago
17 changed files with 230 additions and 12 deletions
@ -0,0 +1,12 @@ |
|||||||
|
plugins { |
||||||
|
id("io.element.android-compose") |
||||||
|
} |
||||||
|
|
||||||
|
android { |
||||||
|
namespace = "io.element.android.x.libraries.avatar" |
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
implementation(project(":libraries:matrix")) |
||||||
|
implementation(libs.coil.compose) |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
# Add project specific ProGuard rules here. |
||||||
|
# You can control the set of applied configuration files using the |
||||||
|
# proguardFiles setting in build.gradle. |
||||||
|
# |
||||||
|
# For more details, see |
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html |
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following |
||||||
|
# and specify the fully qualified class name to the JavaScript interface |
||||||
|
# class: |
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||||
|
# public *; |
||||||
|
#} |
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for |
||||||
|
# debugging stack traces. |
||||||
|
#-keepattributes SourceFile,LineNumberTable |
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to |
||||||
|
# hide the original source file name. |
||||||
|
#-renamesourcefileattribute SourceFile |
@ -0,0 +1,24 @@ |
|||||||
|
package io.element.android.x.avatar |
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry |
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4 |
||||||
|
|
||||||
|
import org.junit.Test |
||||||
|
import org.junit.runner.RunWith |
||||||
|
|
||||||
|
import org.junit.Assert.* |
||||||
|
|
||||||
|
/** |
||||||
|
* Instrumented test, which will execute on an Android device. |
||||||
|
* |
||||||
|
* See [testing documentation](http://d.android.com/tools/testing). |
||||||
|
*/ |
||||||
|
@RunWith(AndroidJUnit4::class) |
||||||
|
class ExampleInstrumentedTest { |
||||||
|
@Test |
||||||
|
fun useAppContext() { |
||||||
|
// Context of the app under test. |
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext |
||||||
|
assertEquals("io.element.android.x.avatar.test", appContext.packageName) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
|
||||||
|
</manifest> |
@ -0,0 +1,33 @@ |
|||||||
|
package io.element.android.x.avatar |
||||||
|
|
||||||
|
import android.util.Log |
||||||
|
import androidx.compose.foundation.Image |
||||||
|
import androidx.compose.foundation.border |
||||||
|
import androidx.compose.foundation.layout.size |
||||||
|
import androidx.compose.foundation.shape.CircleShape |
||||||
|
import androidx.compose.material3.MaterialTheme |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import androidx.compose.ui.draw.clip |
||||||
|
import androidx.compose.ui.unit.dp |
||||||
|
import coil.compose.rememberAsyncImagePainter |
||||||
|
|
||||||
|
/** |
||||||
|
* TODO fallback Avatar |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
fun Avatar(avatarData: AvatarData) { |
||||||
|
Image( |
||||||
|
painter = rememberAsyncImagePainter( |
||||||
|
model = avatarData.url, |
||||||
|
onError = { |
||||||
|
Log.e("TAG", "Error $it\n${it.result}", it.result.throwable) |
||||||
|
}), |
||||||
|
contentDescription = null, |
||||||
|
modifier = Modifier |
||||||
|
.size(avatarData.size) |
||||||
|
.clip(CircleShape) |
||||||
|
.border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape) |
||||||
|
) |
||||||
|
} |
||||||
|
|
@ -0,0 +1,10 @@ |
|||||||
|
package io.element.android.x.avatar |
||||||
|
|
||||||
|
import androidx.compose.ui.unit.Dp |
||||||
|
import androidx.compose.ui.unit.dp |
||||||
|
|
||||||
|
data class AvatarData( |
||||||
|
val url: String, |
||||||
|
val size: Dp = 48.dp |
||||||
|
) |
||||||
|
|
@ -0,0 +1,41 @@ |
|||||||
|
package io.element.android.x.avatar |
||||||
|
|
||||||
|
import coil.ImageLoader |
||||||
|
import coil.fetch.FetchResult |
||||||
|
import coil.fetch.Fetcher |
||||||
|
import coil.request.Options |
||||||
|
import io.element.android.x.matrix.MatrixClient |
||||||
|
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl |
||||||
|
|
||||||
|
class AvatarFetcher( |
||||||
|
private val matrixClient: MatrixClient, |
||||||
|
private val avatarData: AvatarData, |
||||||
|
private val options: Options, |
||||||
|
private val imageLoader: ImageLoader |
||||||
|
) : |
||||||
|
Fetcher { |
||||||
|
|
||||||
|
override suspend fun fetch(): FetchResult? { |
||||||
|
val mediaSource = mediaSourceFromUrl(avatarData.url) |
||||||
|
val mediaContent = matrixClient.loadMediaContentForSource(mediaSource) |
||||||
|
return mediaContent.fold( |
||||||
|
{ mediaContent -> |
||||||
|
val byteArray = mediaContent.toUByteArray().toByteArray() |
||||||
|
val fetcher = imageLoader.components.newFetcher(byteArray, options, imageLoader) |
||||||
|
fetcher?.first?.fetch() |
||||||
|
}, |
||||||
|
{null} |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
class Factory(private val matrixClient: MatrixClient) : Fetcher.Factory<AvatarData> { |
||||||
|
|
||||||
|
override fun create( |
||||||
|
data: AvatarData, |
||||||
|
options: Options, |
||||||
|
imageLoader: ImageLoader |
||||||
|
): Fetcher? { |
||||||
|
return AvatarFetcher(matrixClient, data, options, imageLoader) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
package io.element.android.x.avatar |
||||||
|
|
||||||
|
import org.junit.Test |
||||||
|
|
||||||
|
import org.junit.Assert.* |
||||||
|
|
||||||
|
/** |
||||||
|
* Example local unit test, which will execute on the development machine (host). |
||||||
|
* |
||||||
|
* See [testing documentation](http://d.android.com/tools/testing). |
||||||
|
*/ |
||||||
|
class ExampleUnitTest { |
||||||
|
@Test |
||||||
|
fun addition_isCorrect() { |
||||||
|
assertEquals(4, 2 + 2) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue