@@ -40,23 +40,31 @@ import im.vector.app.features.displayname.getBestName
40
40
import im.vector.app.features.home.AvatarRenderer
41
41
import im.vector.app.features.html.PillImageSpan
42
42
import im.vector.app.features.themes.ThemeUtils
43
+ import io.element.android.wysiwyg.EditorEditText
44
+ import org.matrix.android.sdk.api.session.Session
45
+ import org.matrix.android.sdk.api.session.permalinks.PermalinkService
43
46
import org.matrix.android.sdk.api.session.room.model.RoomSummary
44
47
import org.matrix.android.sdk.api.util.MatrixItem
45
48
import org.matrix.android.sdk.api.util.toEveryoneInRoomMatrixItem
46
49
import org.matrix.android.sdk.api.util.toMatrixItem
47
50
import org.matrix.android.sdk.api.util.toRoomAliasMatrixItem
51
+ import timber.log.Timber
48
52
49
53
class AutoCompleter @AssistedInject constructor(
50
54
@Assisted val roomId : String ,
51
55
@Assisted val isInThreadTimeline : Boolean ,
56
+ private val session : Session ,
52
57
private val avatarRenderer : AvatarRenderer ,
53
58
private val commandAutocompletePolicy : CommandAutocompletePolicy ,
54
59
autocompleteCommandPresenterFactory : AutocompleteCommandPresenter .Factory ,
55
60
private val autocompleteMemberPresenterFactory : AutocompleteMemberPresenter .Factory ,
56
61
private val autocompleteRoomPresenter : AutocompleteRoomPresenter ,
57
- private val autocompleteEmojiPresenter : AutocompleteEmojiPresenter
62
+ private val autocompleteEmojiPresenter : AutocompleteEmojiPresenter ,
58
63
) {
59
64
65
+ private val permalinkService: PermalinkService
66
+ get() = session.permalinkService()
67
+
60
68
private lateinit var autocompleteMemberPresenter: AutocompleteMemberPresenter
61
69
62
70
@AssistedFactory
@@ -79,6 +87,7 @@ class AutoCompleter @AssistedInject constructor(
79
87
}
80
88
81
89
private lateinit var glideRequests: GlideRequests
90
+ private val autocompletes: MutableSet <Autocomplete <* >> = hashSetOf()
82
91
83
92
fun setup (editText : EditText ) {
84
93
this .editText = editText
@@ -90,26 +99,41 @@ class AutoCompleter @AssistedInject constructor(
90
99
setupRooms(backgroundDrawable, editText)
91
100
}
92
101
102
+ fun setEnabled (isEnabled : Boolean ) =
103
+ autocompletes.forEach {
104
+ if (! isEnabled) { it.dismissPopup() }
105
+ it.setEnabled(isEnabled)
106
+ }
107
+
93
108
fun clear () {
94
109
this .editText = null
95
110
autocompleteEmojiPresenter.clear()
96
111
autocompleteRoomPresenter.clear()
97
112
autocompleteCommandPresenter.clear()
98
113
autocompleteMemberPresenter.clear()
114
+ autocompletes.forEach {
115
+ it.setEnabled(false )
116
+ it.dismissPopup()
117
+ }
118
+ autocompletes.clear()
99
119
}
100
120
101
121
private fun setupCommands (backgroundDrawable : Drawable , editText : EditText ) {
102
- Autocomplete .on<Command >(editText)
122
+ autocompletes + = Autocomplete .on<Command >(editText)
103
123
.with (commandAutocompletePolicy)
104
124
.with (autocompleteCommandPresenter)
105
125
.with (ELEVATION_DP )
106
126
.with (backgroundDrawable)
107
127
.with (object : AutocompleteCallback <Command > {
108
128
override fun onPopupItemClicked (editable : Editable , item : Command ): Boolean {
109
- editable.clear()
110
- editable
111
- .append(item.command)
112
- .append(" " )
129
+ if (editText is EditorEditText ) {
130
+ editText.replaceTextSuggestion(item.command)
131
+ } else {
132
+ editable.clear()
133
+ editable
134
+ .append(item.command)
135
+ .append(" " )
136
+ }
113
137
return true
114
138
}
115
139
@@ -121,24 +145,22 @@ class AutoCompleter @AssistedInject constructor(
121
145
122
146
private fun setupMembers (backgroundDrawable : ColorDrawable , editText : EditText ) {
123
147
autocompleteMemberPresenter = autocompleteMemberPresenterFactory.create(roomId)
124
- Autocomplete .on<AutocompleteMemberItem >(editText)
148
+ autocompletes + = Autocomplete .on<AutocompleteMemberItem >(editText)
125
149
.with (CharPolicy (TRIGGER_AUTO_COMPLETE_MEMBERS , true ))
126
150
.with (autocompleteMemberPresenter)
127
151
.with (ELEVATION_DP )
128
152
.with (backgroundDrawable)
129
153
.with (object : AutocompleteCallback <AutocompleteMemberItem > {
130
154
override fun onPopupItemClicked (editable : Editable , item : AutocompleteMemberItem ): Boolean {
131
- return when (item) {
132
- is AutocompleteMemberItem .Header -> false // do nothing header is not clickable
133
- is AutocompleteMemberItem .RoomMember -> {
134
- insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS , item.roomMemberSummary.toMatrixItem())
135
- true
136
- }
137
- is AutocompleteMemberItem .Everyone -> {
138
- insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS , item.roomSummary.toEveryoneInRoomMatrixItem())
139
- true
140
- }
141
- }
155
+ val matrixItem = when (item) {
156
+ is AutocompleteMemberItem .Header -> null // do nothing header is not clickable
157
+ is AutocompleteMemberItem .RoomMember -> item.roomMemberSummary.toMatrixItem()
158
+ is AutocompleteMemberItem .Everyone -> item.roomSummary.toEveryoneInRoomMatrixItem()
159
+ } ? : return false
160
+
161
+ insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS , matrixItem)
162
+
163
+ return true
142
164
}
143
165
144
166
override fun onPopupVisibilityChanged (shown : Boolean ) {
@@ -148,7 +170,7 @@ class AutoCompleter @AssistedInject constructor(
148
170
}
149
171
150
172
private fun setupRooms (backgroundDrawable : ColorDrawable , editText : EditText ) {
151
- Autocomplete .on<RoomSummary >(editText)
173
+ autocompletes + = Autocomplete .on<RoomSummary >(editText)
152
174
.with (CharPolicy (TRIGGER_AUTO_COMPLETE_ROOMS , true ))
153
175
.with (autocompleteRoomPresenter)
154
176
.with (ELEVATION_DP )
@@ -166,7 +188,10 @@ class AutoCompleter @AssistedInject constructor(
166
188
}
167
189
168
190
private fun setupEmojis (backgroundDrawable : Drawable , editText : EditText ) {
169
- Autocomplete .on<String >(editText)
191
+ // Rich text editor is not yet supported
192
+ if (editText is EditorEditText ) return
193
+
194
+ autocompletes + = Autocomplete .on<String >(editText)
170
195
.with (CharPolicy (TRIGGER_AUTO_COMPLETE_EMOJIS , false ))
171
196
.with (autocompleteEmojiPresenter)
172
197
.with (ELEVATION_DP )
@@ -197,7 +222,41 @@ class AutoCompleter @AssistedInject constructor(
197
222
.build()
198
223
}
199
224
200
- private fun insertMatrixItem (editText : EditText , editable : Editable , firstChar : Char , matrixItem : MatrixItem ) {
225
+ private fun insertMatrixItem (editText : EditText , editable : Editable , firstChar : Char , matrixItem : MatrixItem ) =
226
+ if (editText is EditorEditText ) {
227
+ insertMatrixItemIntoRichTextEditor(editText, matrixItem)
228
+ } else {
229
+ insertMatrixItemIntoEditable(editText, editable, firstChar, matrixItem)
230
+ }
231
+
232
+ private fun insertMatrixItemIntoRichTextEditor (editorEditText : EditorEditText , matrixItem : MatrixItem ) {
233
+ if (matrixItem is MatrixItem .EveryoneInRoomItem ) {
234
+ editorEditText.replaceTextSuggestion(matrixItem.displayName)
235
+ return
236
+ }
237
+
238
+ val permalink = permalinkService.createPermalink(matrixItem.id)
239
+
240
+ if (permalink == null ) {
241
+ Timber .e(NullPointerException (" Cannot autocomplete as permalink is null" ))
242
+ return
243
+ }
244
+
245
+ val linkText = when (matrixItem) {
246
+ is MatrixItem .RoomAliasItem ,
247
+ is MatrixItem .RoomItem ,
248
+ is MatrixItem .SpaceItem ->
249
+ matrixItem.id
250
+ is MatrixItem .EveryoneInRoomItem ,
251
+ is MatrixItem .UserItem ,
252
+ is MatrixItem .EventItem ->
253
+ matrixItem.getBestName()
254
+ }
255
+
256
+ editorEditText.setLinkSuggestion(url = permalink, text = linkText)
257
+ }
258
+
259
+ private fun insertMatrixItemIntoEditable (editText : EditText , editable : Editable , firstChar : Char , matrixItem : MatrixItem ) {
201
260
// Detect last firstChar and remove it
202
261
var startIndex = editable.lastIndexOf(firstChar)
203
262
if (startIndex == - 1 ) {
0 commit comments