From 7dd15af6d3c8c35969df8fbfacbf80a82c6c2431 Mon Sep 17 00:00:00 2001 From: jonnyandrew Date: Thu, 2 Mar 2023 15:48:36 +0000 Subject: [PATCH] [Rich text editor] Add ability to insert GIFs from keyboard (#8185) Closes vector-im/verticals-internal#21 --- changelog.d/8185.feature | 1 + .../room/detail/composer/ComposerEditText.kt | 29 +++--------- .../detail/composer/RichTextComposerLayout.kt | 12 +++++ .../composer/images/UriContentListener.kt | 45 +++++++++++++++++++ 4 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 changelog.d/8185.feature create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/composer/images/UriContentListener.kt diff --git a/changelog.d/8185.feature b/changelog.d/8185.feature new file mode 100644 index 0000000000..3e1f10d438 --- /dev/null +++ b/changelog.d/8185.feature @@ -0,0 +1 @@ +[Rich text editor] Add ability to insert GIFs from keyboard \ No newline at end of file diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt index 9e88882866..f0014f4ecd 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/ComposerEditText.kt @@ -17,7 +17,6 @@ package im.vector.app.features.home.room.detail.composer -import android.content.ClipData import android.content.Context import android.net.Uri import android.os.Build @@ -27,12 +26,12 @@ import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputConnection import androidx.annotation.RequiresApi import androidx.appcompat.widget.AppCompatEditText -import androidx.core.view.OnReceiveContentListener import androidx.core.view.ViewCompat import androidx.core.view.inputmethod.EditorInfoCompat import androidx.core.view.inputmethod.InputConnectionCompat import im.vector.app.core.extensions.ooi import im.vector.app.core.platform.SimpleTextWatcher +import im.vector.app.features.home.room.detail.composer.images.UriContentListener import im.vector.app.features.html.PillImageSpan import timber.log.Timber @@ -56,27 +55,11 @@ class ComposerEditText @JvmOverloads constructor( EditorInfoCompat.setContentMimeTypes(editorInfo, mimeTypes) ic = InputConnectionCompat.createWrapper(this, ic, editorInfo) - val onReceiveContentListener = OnReceiveContentListener { _, payload -> - val split = payload.partition { item -> item.uri != null } - val uriContent = split.first - val remaining = split.second - - if (uriContent != null) { - val clip: ClipData = uriContent.clip - for (i in 0 until clip.itemCount) { - val uri = clip.getItemAt(i).uri - // ... app-specific logic to handle the URI ... - callback?.onRichContentSelected(uri) - } - } - // Return anything that we didn't handle ourselves. This preserves the default platform - // behavior for text and anything else for which we are not implementing custom handling. - // Return anything that we didn't handle ourselves. This preserves the default platform - // behavior for text and anything else for which we are not implementing custom handling. - remaining - } - - ViewCompat.setOnReceiveContentListener(this, mimeTypes, onReceiveContentListener) + ViewCompat.setOnReceiveContentListener( + this, + mimeTypes, + UriContentListener { callback?.onRichContentSelected(it) } + ) return ic } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt index a13ef25d62..a821458939 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt @@ -36,6 +36,7 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.constraintlayout.widget.ConstraintSet import androidx.core.text.toSpannable +import androidx.core.view.ViewCompat import androidx.core.view.isGone import androidx.core.view.isInvisible import androidx.core.view.isVisible @@ -47,6 +48,7 @@ import im.vector.app.core.extensions.showKeyboard import im.vector.app.core.utils.DimensionConverter import im.vector.app.databinding.ComposerRichTextLayoutBinding import im.vector.app.databinding.ViewRichTextMenuButtonBinding +import im.vector.app.features.home.room.detail.composer.images.UriContentListener import io.element.android.wysiwyg.EditorEditText import io.element.android.wysiwyg.inputhandlers.models.InlineFormat import io.element.android.wysiwyg.inputhandlers.models.LinkAction @@ -188,6 +190,16 @@ internal class RichTextComposerLayout @JvmOverloads constructor( views.plainTextComposerEditText.addTextChangedListener( TextChangeListener({ callback?.onTextChanged(it) }, { updateTextFieldBorder(isFullScreen) }) ) + ViewCompat.setOnReceiveContentListener( + views.richTextComposerEditText, + arrayOf("image/*"), + UriContentListener { callback?.onRichContentSelected(it) } + ) + ViewCompat.setOnReceiveContentListener( + views.plainTextComposerEditText, + arrayOf("image/*"), + UriContentListener { callback?.onRichContentSelected(it) } + ) disallowParentInterceptTouchEvent(views.richTextComposerEditText) disallowParentInterceptTouchEvent(views.plainTextComposerEditText) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/images/UriContentListener.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/images/UriContentListener.kt new file mode 100644 index 0000000000..da0152fd9e --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/images/UriContentListener.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.composer.images + +import android.content.ClipData +import android.net.Uri +import android.view.View +import androidx.core.view.ContentInfoCompat +import androidx.core.view.OnReceiveContentListener + +class UriContentListener( + private val onContent: (uri: Uri) -> Unit +) : OnReceiveContentListener { + override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? { + val split = payload.partition { item -> item.uri != null } + val uriContent = split.first + val remaining = split.second + + if (uriContent != null) { + val clip: ClipData = uriContent.clip + for (i in 0 until clip.itemCount) { + val uri = clip.getItemAt(i).uri + // ... app-specific logic to handle the URI ... + onContent(uri) + } + } + // Return anything that we didn't handle ourselves. This preserves the default platform + // behavior for text and anything else for which we are not implementing custom handling. + return remaining + } +}