I am trying to make a chat in jetpack compose, and I want to be able to use the standard gif keyboard on my samsung to send a gif.
When I click a GIF on a normal TextField, I am currently getting a message "Can't enter this content here"
I found something called Commit Content API which should make it possible to add a GIF in a old EditText so I am trying that inside an AndroidView, Now I dont get the error message anymore, But I also don't have a clue where the GIF is and how it is represented.
AndroidView(factory = {
val editText = @SuppressLint("AppCompatCustomView")
object : EditText(it) {
override fun setOnReceiveContentListener(
mimeTypes: Array<out String>?,
listener: OnReceiveContentListener?
) {
super.setOnReceiveContentListener(mimeTypes, listener)
}
override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection {
val ic: InputConnection = super.onCreateInputConnection(editorInfo)
EditorInfoCompat.setContentMimeTypes(editorInfo, arrayOf("image/gif"))
val callback =
InputConnectionCompat.OnCommitContentListener { inputContentInfo, _, _ ->
try {
inputContentInfo.requestPermission()
} catch (e: Exception) {
return@OnCommitContentListener false
}
true // return true if succeeded
}
return InputConnectionCompat.createWrapper(ic, editorInfo, callback)
}
}
editText
}) {}
callback
is called each time a GIF is selected. You can get the URI from inputContentInfo
:
val callback =
InputConnectionCompat.OnCommitContentListener { inputContentInfo, _, _ ->
try {
inputContentInfo.requestPermission()
} catch (e: Exception) {
return@OnCommitContentListener false
}
gifUri = inputContentInfo.contentUri
true // return true if succeeded
}
Perfectly, you should copy the file from this URI into your own storage and call inputContentInfo.releasePermission()
, because contentUri
will be freed at some point. More info can be found in the documentation.
You can display the content of this URI using Coil as showed in this answer. Note that you need to add the dependency io.coil-kt:coil-gif:$coil_version
A full working example:
var gifUri by remember { mutableStateOf<Uri?>(null) }
val context = LocalContext.current
Image(
rememberImagePainter(
gifUri,
imageLoader = remember {
ImageLoader(context).newBuilder()
.componentRegistry {
if (SDK_INT >= 28) {
add(ImageDecoderDecoder(context))
} else {
add(GifDecoder())
}
}.build()
}
),
contentDescription = null,
modifier = Modifier.size(300.dp)
)
AndroidView(factory = { context ->
val editText = @SuppressLint("AppCompatCustomView")
object : EditText(context) {
override fun setOnReceiveContentListener(
mimeTypes: Array<out String>?,
listener: OnReceiveContentListener?
) {
super.setOnReceiveContentListener(mimeTypes, listener)
}
override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection {
val ic: InputConnection = super.onCreateInputConnection(editorInfo)
EditorInfoCompat.setContentMimeTypes(editorInfo, arrayOf("image/gif"))
val callback =
InputConnectionCompat.OnCommitContentListener { inputContentInfo, _, _ ->
try {
inputContentInfo.requestPermission()
} catch (e: Exception) {
return@OnCommitContentListener false
}
gifUri = inputContentInfo.contentUri
true // return true if succeeded
}
return InputConnectionCompat.createWrapper(ic, editorInfo, callback)
}
}
editText
}) {}