Compose Image not visible - android

I take uri from db and would like to show an image:
val uri by viewModel.uri.collectAsState()
Image(
painter = rememberAsyncImagePainter(
ImageRequest
.Builder(LocalContext.current)
.data(data = uri)
.build()
),
contentDescription = ""
)
but it is not loading - it is blank.
When debugging I can see that on recomposition
Image->Uri->uriString is set to correct value - "content://com.android.providers.media.documents/document/image%3A44"
but itis still not visible.
It is only visible if I pick it again using:
val pickMedia =
rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) {
viewModel.onImageSelected(uri)
} else {
Log.d("PhotoPicker", "No media selected")
}
}
I am reusing the same image in many places and from now on it is visible everywhere (but still no other image is visible until I repick it again).
After closing and reopening app images are not visible again.
Maybe it is some caching? or permissions?

Related

Make a SmallImage complication with an ambient image

I'm trying to make a WearOS Complication that is just an image. Ideally, it should display the image img1.png when on like this, and the image outlines.png when in ambient mode like this.
Right now, I've got
return when (request.complicationType) {
ComplicationType.SMALL_IMAGE -> SmallImageComplicationData.Builder(
smallImage = SmallImage.Builder(
Icon.createWithResource(this, R.drawable.img1), SmallImageType.PHOTO).build(),
contentDescription = PlainComplicationText
.Builder(text = "Sample text").build()
)
.setTapAction(complicationPendingIntent)
.build()
else -> {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unexpected complication type ${request.complicationType}")
}
null
}
}
and I want to add the ambient image somewhere but don't know how. This code sample is inside the onComplicationRequest function, which returns ComplicationData? by the way. I have the same issue with
override fun getPreviewData(type: ComplicationType): ComplicationData {
return SmallImageComplicationData.Builder(
smallImage = SmallImage.Builder(
Icon.createWithResource(this, R.drawable.img1), SmallImageType.PHOTO).build(),
contentDescription = PlainComplicationText
.Builder(text = "Your loved one's images!").build()
)
.setTapAction(null)
.build()
}
which again, returns ComplicationData. Any ideas? Thanks!
(The documentation for WearOS development is pretty incomplete imo :P)
It's on SmallImage.Builder
https://developer.android.com/reference/androidx/wear/watchface/complications/data/SmallImage.Builder#setAmbientImage(android.graphics.drawable.Icon)
Try
SmallImageComplicationData.Builder(
smallImage = SmallImage.Builder(
Icon.createWithResource(this, R.drawable.img1), SmallImageType.PHOTO)
.setAmbientImage(...)
.build(),
contentDescription = PlainComplicationText
.Builder(text = "Sample text").build()
)
.setTapAction(complicationPendingIntent)
.build()

Index out of bound in painterResource() when updating BottomNavigation

I'm currently getting an index out of bound which I can't figure out why...
Following situation:
Sometimes I update my compose bottom navigation to add an item or to change tint color etc. When the app is running and the update is happening it works. But when i close the app and it starts to initialize the navigation with the new state I get an index out of bound exception on the painterResource...
Would be nice if anyone has a hint for me. Another thing to add is i wire the compose currently to xml but i can't see a problem with that.
Thanks in advance
BottomNavigation(
backgroundColor = backgroundColor,
) {
navigation.navigationItems.forEach { navigationItem ->
val isSelected = selectedItem == navigationItem.destination
val iconResId =
if (isSelected) navigationItem.selectedIconRes else navigationItem.iconRes
val hasBadge = badges.contains(navigationItem.destination)
BottomNavigationItem(
icon = {
if (hasBadge) {
BadgedBox(
modifier = Modifier.background(badgeBackgroundColor),
badge = { Badge(backgroundColor = badgeColor) }
) {
Icon(
painterResource(iconResId),
contentDescription = null
)
}
} else {
Icon(
painterResource(iconResId),
contentDescription = null
)
}
},
selected = isSelected,
onClick = { onItemSelected(navigationItem.destination) },
alwaysShowLabel = true,
selectedContentColor = selectedTintColor,
unselectedContentColor = tintColor
)
}
}
Update:
I found now out why it happens but it’s still strange. The drawable itself produced somehow that error. After putting a different one there it worked all the time. The question is why did it not work after restarting the app but when running on the dynamic change… I have no idea…
Update 2:
After the dynamic change there are artifacts happening within the icons… For example 3rd icon has artifacts of 4th etc. What could cause that? Any idea?

Using Coil ImageRequest target causes image not to load

In the Coil image library I am trying to get when the image has been successfully loaded and then use Palette to get the colors from the bitmap but I am having a problem where if I use the ImageRequests's target the image does not show in the imageview but the onSuccess completes correctly because I am able to extract the color from the given bitmap
Here is what I have
_contentImage.load(File(image))
{
crossfade(true)
allowHardware(false)
listener(onError = { _, error ->
Log.d(SUBTAG, "Error -> ${error.message}")
},
onSuccess = {_, _ ->
Log.d(SUBTAG, "Content image loaded")
contentImageLoaded = true
checkContentLoaded()
})
target(
onSuccess = { result ->
Palette.from(result.toBitmap()).generate {
if (it != null) {
val paletteColor = it.getDominantColor(color)
_constraintLayout.setBackgroundColor(paletteColor)
}
}
}
)
}
If I comment out the whole target section of the builder the image shows fine but obviously I don't get the palette stuff
Do I have to manually set the drawable to the image if I use the onSuccess like this
target(
onSuccess = { result ->
Palette.from(result.toBitmap()).generate {
if (it != null) {
val paletteColor = it.getDominantColor(color)
_constraintLayout.setBackgroundColor(paletteColor)
}
}
_contentImage.setImageDrawable(result) // Set it here?
}
)
If I do that the image shows but it seems odd to have to manually set it and I feel like it should be set by itself
Not sure what the problem is here

displaying image using Uri -> from image picker works but from db room don't... (Jetpack Compose)

I have a caller app that allows the user to pick up photos for the contacts and audio files for the ringtones from their mobile.
When I pick up the photo, it can be displayed correctly using the URI on the interface. on both the main page and contact page.
and i save it inside the room database...
if i close the app and reopen it, it gets the same URI from db. but no image is displayed. neither on the main page or contact page.
i tried to insert the URI code manually it didn't display anything as well... also change the image loader to GlideImage from rememberImagePainter (another implementation) but same issue...
the URI i have from db and image picker looks like this
val uri2:Uri = "content://com.android.providers.media.documents/document/image%3A34".toUri()
the code the pick up the image Uri is this
class GetContentActivityResult(
private val launcher: ManagedActivityResultLauncher<String, Uri>,
val uri: Uri?
) {
fun launch(mimeType: String) {
launcher.launch(mimeType)
}
}
#Composable
fun rememberGetContentActivityResult(): GetContentActivityResult {
var uri by rememberSaveable { mutableStateOf<Uri?>(null) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent(), onResult = {
uri = it
})
return remember(launcher, uri) { GetContentActivityResult(launcher, uri) }
}
i display the image  in the contact page like this
val getContent = rememberGetContentActivityResult() <-- to access the class of pickup files
if (roomViewModel.photoUri.value.isBlank()){ <-- if no image from db display the picked image using image picker
getContent.uri?.let {
Image(
modifier = Modifier
.align(Alignment.TopCenter)
.fillMaxSize(1f),
contentDescription = "UserImage",
contentScale = ContentScale.Crop,
painter = rememberImagePainter(data = it))
}
}else{
Image(
modifier = Modifier
.align(Alignment.TopCenter)
.fillMaxSize(1f),
contentDescription = "UserImage",
contentScale = ContentScale.Crop,
painter = rememberImagePainter(data = roomViewModel.photoUri.value))
}
}
TextButton(
onClick = { getContent.launch("image/*") }, <-- launching the class to get the image URI by defining the Mime as image/*
modifier = Modifier.layoutId("changePhoto")
) {
Text(
text = "Change Photo",
color = Color.Black)}
inside the main page. there is no image picker, i just display the data that i have in the Database, and i display the image this way
#OptIn(ExperimentalCoilApi::class)
#Composable
fun ProfilePicture(uri : Uri, imageSize: Dp) {
Card(
shape = CircleShape,
border = BorderStroke(
width = 2.dp,
color = Color.Red ),
modifier = Modifier.padding(16.dp),
elevation = 4.dp) {
val uri2:Uri = "content://com.android.providers.media.documents/document/image%3A34".toUri() //<-- i tried to load the image this way also it didn't work.
val painter = rememberImagePainter(
data = uri,
builder = {
placeholder(R.drawable.yara) <-- the placeholder image blinks quickly when app is loaded and then disappear...
}
)
Image(
painter = painter,
contentDescription = "User Image",
modifier = Modifier.size(imageSize) )
}
}
Is it an issue with the Uri picker or image display?
other content from room db are displayed correctly (strings)
i tried to use the code on emulator and real device and it is the same for both cases...
one thing i just noticed... if i used the image picker and pick a previously picked image (it's uri is in the db) the image is displayed on the other locations in the app automatically without doing anything else... just picking the image and displaying it without saving it even...
Well, I didn't know how to do the takePersistableUriPermission(), I'm still learning. But I created a converter class (the longest way solution) to use the Uri to convert it to bit map... but i have to make it drawable first. I didn't know how to do it bitmap from Uri directly.
I updated the data class in the first place
#Entity
data class Contact(
#PrimaryKey()
val id: UUID = UUID.randomUUID(),
val name: String,
val land_line : String,
val mobile: String,
val contact_photo: Bitmap
)
Added a TypeConverter for the bitmap in database
#TypeConverter
fun fromBitmap(bitmap: Bitmap): ByteArray {
val outputStream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
return outputStream.toByteArray()
}
#TypeConverter
fun toBitmap(byteArray: ByteArray): Bitmap {
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
Changed the values types all the way to UI, and created a converter class in the Util package to convert the Uri into drawable then Bitmap (I know it looks stupid - any better solution is accepted).
suspend fun convertToBitmap(uri: Uri, context: Context, widthPixels: Int, heightPixels: Int): Bitmap? {
val mutableBitmap = Bitmap.createBitmap(widthPixels, heightPixels, Bitmap.Config.ARGB_8888)
val canvas = Canvas(mutableBitmap)
val drawable = getDrawable(uri, context)
drawable?.setBounds(0, 0, widthPixels, heightPixels)
drawable?.draw(canvas)
return mutableBitmap
}
#OptIn(ExperimentalCoilApi::class)
suspend fun getDrawable(uri: Uri, context: Context): Drawable? {
val imageLoader = ImageLoader.Builder(context)
.availableMemoryPercentage(0.25)
.allowHardware(false)
.crossfade(true)
.build()
val request= ImageRequest.Builder(context)
.data(uri)
.build()
return imageLoader.execute(request).drawable
}
It is working now and loading perfectly. I know that I have the width and height by 50 50 px, but this is a test anyway.

How to add listener in recyclerview when image is ready for display

Currently, I have an app that uses Picasso to download images and display them in a recyclerview.
I want to change my logic by totally doing away with Picasso and downloading images in the background when the app is initially installed. During succeeding runs of the app, the images will be displayed from internal storage.
So, how would I let the recyclerview know that the image is ready for display after it has been successfully saved in internal storage? I'd prefer if they aren't shown all at once because that would take too long, but show each image as the download is completed (kind of similar to how Picasso does it).
This is my current onBindViewHolder code:
override fun onBindViewHolder(rawHolder: RecyclerView.ViewHolder, position: Int) {
val holder = rawHolder as CustomVH
holder.resourcesByCategory = resourcesByCategory[position]
val dir : String = utils.getInternalDirectory("Covers") + "/CoverBookId" + resourcesByCategory[position].id + ".jpg"
val bookCover = File(dir)
if (bookCover.exists()) {
if (holder.bmp != null) {
holder.bmp!!.recycle()
}
holder.resourceCover.setImageBitmap(null)
val options = BitmapFactory.Options()
options.inPreferredConfig = Bitmap.Config.RGB_565
holder.bmp = BitmapFactory.decodeStream(FileInputStream(bookCover), null, options)
if (holder.bmp != null) {
holder.bmp = Bitmap.createScaledBitmap(holder.bmp, 150,180, true)
holder.resourceCover.setImageBitmap(holder.bmp!!)
}
}
}

Categories

Resources