Skip to content

Commit

Permalink
add image block component
Browse files Browse the repository at this point in the history
  • Loading branch information
Siddharth Agarwal committed Oct 3, 2023
1 parent 6ac006c commit 8e30520
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.hisp.dhis.common.screens

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import org.hisp.dhis.mobile.ui.designsystem.component.ImageBlock
import java.io.File

@Composable
fun ImageBlockScreen() {
ImageBlock(
painter = painterResource("image/sample.png"),
file = File("/data/data/org.hisp.dhis.android/files/sample.jpg"),
onClick = {},
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.hisp.dhis.mobile.ui.designsystem.component.internal.image

import android.graphics.BitmapFactory
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import java.io.File

internal actual class ImageProvider {
actual fun provideImageFromFile(file: File): ImageBitmap? {
return try {
BitmapFactory.decodeFile(file.absolutePath).asImageBitmap()
} catch (ex: Exception) {
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,52 +11,60 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.FileDownload
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import org.hisp.dhis.mobile.ui.designsystem.component.internal.image.rememberImageProvider
import org.hisp.dhis.mobile.ui.designsystem.theme.Radius
import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing
import java.io.File

@Composable
fun ImageBlock(
painter: Painter,
file: File,
downloadButtonVisible: Boolean = true,
contentScale: ContentScale = ContentScale.FillBounds,
onClick: () -> Unit,
) {
Box(
modifier = Modifier
.padding(vertical = Spacing.Spacing8),
) {
Image(
val imageBitmap by rememberImageProvider(file)
if (imageBitmap != null) {
Box(
modifier = Modifier
.fillMaxWidth()
.clip(shape = RoundedCornerShape(Radius.S))
.background(Color.Black)
.height(160.dp),
painter = painter,
contentDescription = "",
contentScale = contentScale,
)
.padding(vertical = Spacing.Spacing8)
.testTag("IMAGE_BLOCK_CONTAINER"),
) {
imageBitmap?.let { bitmap ->
Image(
modifier = Modifier
.fillMaxWidth()
.clip(shape = RoundedCornerShape(Radius.S))
.background(Color.Black)
.height(160.dp),
bitmap = bitmap,
contentDescription = null,
contentScale = ContentScale.FillBounds,
)
}

if (downloadButtonVisible) {
SquareIconButton(
enabled = true,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(Spacing.Spacing4),
icon = {
Icon(
imageVector = Icons.Outlined.FileDownload,
contentDescription = "File download Button",
)
},
) {
onClick.invoke()
if (downloadButtonVisible) {
SquareIconButton(
enabled = true,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(Spacing.Spacing4),
icon = {
Icon(
imageVector = Icons.Outlined.FileDownload,
contentDescription = "File download Button",
)
},
) {
onClick.invoke()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.hisp.dhis.mobile.ui.designsystem.component.internal.image

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.ImageBitmap
import java.io.File

@Composable
internal fun rememberImageProvider(file: File): State<ImageBitmap?> {
val imageProvider = LocalImageProvider.current
val result = remember(file) { mutableStateOf<ImageBitmap?>(null) }

LaunchedEffect(file) {
result.value = imageProvider.provideImageFromFile(file)
}

return result
}

internal expect class ImageProvider() {
fun provideImageFromFile(file: File): ImageBitmap?
}

internal val LocalImageProvider = staticCompositionLocalOf { ImageProvider() }
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.hisp.dhis.mobile.ui.designsystem.component.internal.image

import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.toComposeImageBitmap
import org.jetbrains.skia.Image
import java.io.File

internal actual class ImageProvider {
actual fun provideImageFromFile(file: File): ImageBitmap? {
return try {
Image.makeFromEncoded(file.readBytes()).toComposeImageBitmap()
} catch (ex: Exception) {
null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.hisp.dhis.mobile.ui.designsystem.component

import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import org.junit.Rule
import org.junit.Test
import java.io.File

class ImageBlockTest {

@get:Rule
val rule = createComposeRule()

@Test
fun shouldNotRenderImageBlockIfFileIsNotValid() {
rule.setContent {
ImageBlock(file = File("")) {}
}

rule.onNodeWithTag("IMAGE_BLOCK_CONTAINER").assertDoesNotExist()
}
}

0 comments on commit 8e30520

Please sign in to comment.