Add autocomplete to plain text composer
This commit is contained in:
parent
24614bbbae
commit
3157a35b74
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue