Skip to content

Forms : fix thumbnails mismatch #514

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

Merged
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not possible to inject something unique into the FormAttachmentState at creation time, like a UUID, then use that as the name of the file on disk?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That UUID would need be the same every time to re-fetch the thumbnail on the next launch of the Form. Otherwise, it would end up creating the thumbnail many times as the form is closed and re-opened.

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package com.arcgismaps.toolkit.featureforms.internal.components.attachment
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap.CompressFormat
import android.graphics.Bitmap
import android.media.ThumbnailUtils
import android.os.Build
import android.util.Size
Expand Down Expand Up @@ -50,7 +50,6 @@ import com.arcgismaps.mapping.featureforms.FeatureForm
import com.arcgismaps.mapping.featureforms.FormAttachment
import com.arcgismaps.mapping.featureforms.FormAttachmentType
import com.arcgismaps.toolkit.featureforms.internal.components.base.FormElementState
import com.arcgismaps.toolkit.featureforms.internal.utils.AttachmentsFileProvider
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -59,9 +58,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.Objects


Expand Down Expand Up @@ -298,17 +295,12 @@ internal class FormAttachmentState(
val filePath: String
get() = formAttachment?.filePath ?: ""

private var _thumbnailUri: MutableState<String> = mutableStateOf("")
private var _thumbnail: MutableState<Bitmap?> = mutableStateOf(null)

/**
* The URI of the thumbnail image. This is empty until [load] is called.
* The thumbnail image. This is null until [load] is called.
*/
val thumbnailUri: State<String> = _thumbnailUri

/**
* The directory where the attachments are stored as defined in the [AttachmentsFileProvider].
*/
private val attachmentsDir = "feature_forms_attachments"
val thumbnail: State<Bitmap?> = _thumbnail

/**
* The size of the thumbnail image.
Expand Down Expand Up @@ -387,21 +379,13 @@ internal class FormAttachmentState(
}

/**
* Creates a thumbnail image for the attachment. If the thumbnail already exists, it will not be
* recreated.
* Creates a thumbnail image for the attachment.
*/
private suspend fun createThumbnail() = withContext(Dispatchers.IO) {
if (formAttachment == null) {
return@withContext
}
val directory = File(filesDir, attachmentsDir)
directory.mkdirs()
val file = File(directory, "thumb_$id")
if (file.exists()) {
_thumbnailUri.value = file.absolutePath
return@withContext
}
val bitmap = try {
_thumbnail.value = try {
when (type) {
is FormAttachmentType.Image -> {
formAttachment.createThumbnail(thumbnailSize.width, thumbnailSize.height)
Expand All @@ -420,14 +404,7 @@ internal class FormAttachmentState(
}
} catch (ex: Exception) {
null
} ?: return@withContext

// create and write to the thumbnail file if the bitmap is not null
file.createNewFile()
BufferedOutputStream(FileOutputStream(file)).use { bos ->
bitmap.compress(CompressFormat.JPEG, 85, bos)
}
_thumbnailUri.value = file.absolutePath
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.arcgismaps.toolkit.featureforms.internal.components.attachment

import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.Bitmap
import android.text.format.Formatter
import android.widget.Toast
import androidx.compose.foundation.BorderStroke
Expand Down Expand Up @@ -109,7 +110,7 @@ internal fun AttachmentTile(
) {
val loadStatus by state.loadStatus.collectAsState()
val interactionSource = remember { MutableInteractionSource() }
val thumbnailUri by state.thumbnailUri
val thumbnail by state.thumbnail
val configuration = LocalViewConfiguration.current
val haptic = LocalHapticFeedback.current
var showContextMenu by remember { mutableStateOf(false) }
Expand All @@ -133,7 +134,7 @@ internal fun AttachmentTile(
LoadStatus.Loaded -> LoadedView(
title = state.name,
type = state.type,
thumbnailUri = thumbnailUri
thumbnail = thumbnail
)

LoadStatus.Loading -> DefaultView(
Expand Down Expand Up @@ -262,16 +263,16 @@ internal fun AttachmentTile(
private fun LoadedView(
title: String,
type: FormAttachmentType,
thumbnailUri: String,
thumbnail: Bitmap?,
modifier: Modifier = Modifier
) {
Box(
modifier = modifier
.fillMaxSize()
) {
if (thumbnailUri.isNotEmpty()) {
if (thumbnail != null) {
AsyncImage(
model = thumbnailUri,
model = thumbnail,
contentDescription = "Thumbnail",
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
Expand Down