Add autocomplete to plain text composer

This commit is contained in:
jonnyandrew 2023-05-18 11:05:04 +01:00
parent 24614bbbae
commit 3157a35b74
No known key found for this signature in database
GPG Key ID: 0D58D4EF33D27015
3 changed files with 46 additions and 14 deletions

View File

@ -87,6 +87,7 @@ class AutoCompleter @AssistedInject constructor(
} }
private lateinit var glideRequests: GlideRequests private lateinit var glideRequests: GlideRequests
private val autocompletes: MutableSet<Autocomplete<*>> = hashSetOf()
fun setup(editText: EditText) { fun setup(editText: EditText) {
this.editText = editText this.editText = editText
@ -98,16 +99,27 @@ class AutoCompleter @AssistedInject constructor(
setupRooms(backgroundDrawable, editText) setupRooms(backgroundDrawable, editText)
} }
fun setEnabled(isEnabled: Boolean) =
autocompletes.forEach {
if (!isEnabled) { it.dismissPopup() }
it.setEnabled(isEnabled)
}
fun clear() { fun clear() {
this.editText = null this.editText = null
autocompleteEmojiPresenter.clear() autocompleteEmojiPresenter.clear()
autocompleteRoomPresenter.clear() autocompleteRoomPresenter.clear()
autocompleteCommandPresenter.clear() autocompleteCommandPresenter.clear()
autocompleteMemberPresenter.clear() autocompleteMemberPresenter.clear()
autocompletes.forEach {
it.setEnabled(false)
it.dismissPopup()
}
autocompletes.clear()
} }
private fun setupCommands(backgroundDrawable: Drawable, editText: EditText) { private fun setupCommands(backgroundDrawable: Drawable, editText: EditText) {
Autocomplete.on<Command>(editText) autocompletes += Autocomplete.on<Command>(editText)
.with(commandAutocompletePolicy) .with(commandAutocompletePolicy)
.with(autocompleteCommandPresenter) .with(autocompleteCommandPresenter)
.with(ELEVATION_DP) .with(ELEVATION_DP)
@ -133,7 +145,7 @@ class AutoCompleter @AssistedInject constructor(
private fun setupMembers(backgroundDrawable: ColorDrawable, editText: EditText) { private fun setupMembers(backgroundDrawable: ColorDrawable, editText: EditText) {
autocompleteMemberPresenter = autocompleteMemberPresenterFactory.create(roomId) autocompleteMemberPresenter = autocompleteMemberPresenterFactory.create(roomId)
Autocomplete.on<AutocompleteMemberItem>(editText) autocompletes += Autocomplete.on<AutocompleteMemberItem>(editText)
.with(CharPolicy(TRIGGER_AUTO_COMPLETE_MEMBERS, true)) .with(CharPolicy(TRIGGER_AUTO_COMPLETE_MEMBERS, true))
.with(autocompleteMemberPresenter) .with(autocompleteMemberPresenter)
.with(ELEVATION_DP) .with(ELEVATION_DP)
@ -158,7 +170,7 @@ class AutoCompleter @AssistedInject constructor(
} }
private fun setupRooms(backgroundDrawable: ColorDrawable, editText: EditText) { private fun setupRooms(backgroundDrawable: ColorDrawable, editText: EditText) {
Autocomplete.on<RoomSummary>(editText) autocompletes += Autocomplete.on<RoomSummary>(editText)
.with(CharPolicy(TRIGGER_AUTO_COMPLETE_ROOMS, true)) .with(CharPolicy(TRIGGER_AUTO_COMPLETE_ROOMS, true))
.with(autocompleteRoomPresenter) .with(autocompleteRoomPresenter)
.with(ELEVATION_DP) .with(ELEVATION_DP)
@ -179,7 +191,7 @@ class AutoCompleter @AssistedInject constructor(
// Rich text editor is not yet supported // Rich text editor is not yet supported
if (editText is EditorEditText) return if (editText is EditorEditText) return
Autocomplete.on<String>(editText) autocompletes += Autocomplete.on<String>(editText)
.with(CharPolicy(TRIGGER_AUTO_COMPLETE_EMOJIS, false)) .with(CharPolicy(TRIGGER_AUTO_COMPLETE_EMOJIS, false))
.with(autocompleteEmojiPresenter) .with(autocompleteEmojiPresenter)
.with(ELEVATION_DP) .with(ELEVATION_DP)

View File

@ -125,9 +125,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
private val roomId: String get() = withState(timelineViewModel) { it.roomId } private val roomId: String get() = withState(timelineViewModel) { it.roomId }
private val autoCompleter: AutoCompleter by lazy { private val autoCompleters: MutableMap<EditText, AutoCompleter> = hashMapOf()
autoCompleterFactory.create(roomId, isThreadTimeLine())
}
private val emojiPopup: EmojiPopup by lifecycleAwareLazy { private val emojiPopup: EmojiPopup by lifecycleAwareLazy {
createEmojiPopup() createEmojiPopup()
@ -262,9 +260,8 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
if (!vectorPreferences.isRichTextEditorEnabled()) { autoCompleters.values.forEach(AutoCompleter::clear)
autoCompleter.clear() autoCompleters.clear()
}
messageComposerViewModel.endAllVoiceActions() messageComposerViewModel.endAllVoiceActions()
} }
@ -275,7 +272,12 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
(composer as? View)?.isVisible = messageComposerState.isComposerVisible (composer as? View)?.isVisible = messageComposerState.isComposerVisible
composer.sendButton.isInvisible = !messageComposerState.isSendButtonVisible composer.sendButton.isInvisible = !messageComposerState.isSendButtonVisible
(composer as? RichTextComposerLayout)?.isTextFormattingEnabled = attachmentState.isTextFormattingEnabled (composer as? RichTextComposerLayout)?.also {
val isTextFormattingEnabled = attachmentState.isTextFormattingEnabled
it.isTextFormattingEnabled = isTextFormattingEnabled
autoCompleters[it.richTextEditText]?.setEnabled(isTextFormattingEnabled)
autoCompleters[it.plainTextEditText]?.setEnabled(!isTextFormattingEnabled)
}
} }
private fun setupBottomSheet() { private fun setupBottomSheet() {
@ -316,7 +318,12 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
val composerEditText = composer.editText val composerEditText = composer.editText
composerEditText.setHint(R.string.room_message_placeholder) composerEditText.setHint(R.string.room_message_placeholder)
autoCompleter.setup(composerEditText) (composer as? RichTextComposerLayout)?.let {
initAutoCompleter(it.richTextEditText)
initAutoCompleter(it.plainTextEditText)
} ?: run {
initAutoCompleter(composer.editText)
}
observerUserTyping() observerUserTyping()
@ -412,6 +419,14 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
} }
} }
private fun initAutoCompleter(editText: EditText) {
if (autoCompleters.containsKey(editText)) return
autoCompleters[editText] =
autoCompleterFactory.create(roomId, isThreadTimeLine())
.also { it.setup(editText) }
}
private fun sendTextMessage(text: CharSequence, formattedText: String? = null) { private fun sendTextMessage(text: CharSequence, formattedText: String? = null) {
if (lockSendButton) { if (lockSendButton) {
Timber.w("Send button is locked") Timber.w("Send button is locked")
@ -441,12 +456,12 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
} }
private fun renderRegularMode(content: CharSequence) { private fun renderRegularMode(content: CharSequence) {
autoCompleter.exitSpecialMode() autoCompleters.values.forEach(AutoCompleter::exitSpecialMode)
composer.renderComposerMode(MessageComposerMode.Normal(content)) composer.renderComposerMode(MessageComposerMode.Normal(content))
} }
private fun renderSpecialMode(mode: MessageComposerMode.Special) { private fun renderSpecialMode(mode: MessageComposerMode.Special) {
autoCompleter.enterSpecialMode() autoCompleters.values.forEach(AutoCompleter::enterSpecialMode)
composer.renderComposerMode(mode) composer.renderComposerMode(mode)
} }

View File

@ -106,6 +106,11 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
override val attachmentButton: ImageButton override val attachmentButton: ImageButton
get() = views.attachmentButton get() = views.attachmentButton
val richTextEditText: EditText get() =
views.richTextComposerEditText
val plainTextEditText: EditText get() =
views.plainTextComposerEditText
var pillDisplayHandler: PillDisplayHandler? = null var pillDisplayHandler: PillDisplayHandler? = null
// Border of the EditText // Border of the EditText