@@ -124,35 +124,74 @@ class PlaceholderManager(
124124 val targetSpan = targetItem?.span
125125 val currentType = targetSpan?.attributes?.getValue(TYPE_ATTRIBUTE )
126126 if (currentType != null && shouldMergeItem(currentType)) {
127- val adapter = adapters[type]
128- ? : throw IllegalArgumentException (" Adapter for inserted type not found. Register it with `registerAdapter` method" )
129- val currentAttributes = mutableMapOf<String , String >()
130- val uuid = targetSpan.attributes.getValue(UUID_ATTRIBUTE )
131- for (i in 0 until targetSpan.attributes.length) {
132- val name = targetSpan.attributes.getQName(i)
133- val value = targetSpan.attributes.getValue(name)
134- currentAttributes[name] = value
135- }
136- val updatedAttributes = updateItem(currentAttributes, currentType, targetItem.placeAtStart)
137- val attrs = AztecAttributes ().apply {
138- updatedAttributes.forEach { (key, value) ->
139- setValue(key, value)
140- }
141- }
142- attrs.setValue(UUID_ATTRIBUTE , uuid)
143- attrs.setValue(TYPE_ATTRIBUTE , type)
144- val drawable = buildPlaceholderDrawable(adapter, attrs)
145- val span = AztecPlaceholderSpan (aztecText.context, drawable, 0 , attrs,
146- this , aztecText, WeakReference (adapter), TAG = htmlTag)
147- aztecText.replaceMediaSpan(span) { attributes ->
148- attributes.getValue(UUID_ATTRIBUTE ) == uuid
149- }
150- insertContentOverSpanWithId(uuid)
127+ updateSpan(type, targetItem.span, targetItem.placeAtStart, updateItem, currentType)
151128 } else {
152129 insertItem(type, * updateItem(null , null , false ).toList().toTypedArray())
153130 }
154131 }
155132
133+ private suspend fun updateSpan (
134+ type : String ,
135+ targetSpan : AztecPlaceholderSpan ,
136+ placeAtStart : Boolean ,
137+ updateItem : (currentAttributes: Map <String , String >, currentType: String , placeAtStart: Boolean ) -> Map <String , String >,
138+ currentType : String
139+ ) {
140+ val adapter = adapters[type]
141+ ? : throw IllegalArgumentException (" Adapter for inserted type not found. Register it with `registerAdapter` method" )
142+ val currentAttributes = mutableMapOf<String , String >()
143+ val uuid = targetSpan.attributes.getValue(UUID_ATTRIBUTE )
144+ for (i in 0 until targetSpan.attributes.length) {
145+ val name = targetSpan.attributes.getQName(i)
146+ val value = targetSpan.attributes.getValue(name)
147+ currentAttributes[name] = value
148+ }
149+ val updatedAttributes = updateItem(currentAttributes, currentType, placeAtStart)
150+ val attrs = AztecAttributes ().apply {
151+ updatedAttributes.forEach { (key, value) ->
152+ setValue(key, value)
153+ }
154+ }
155+ attrs.setValue(UUID_ATTRIBUTE , uuid)
156+ attrs.setValue(TYPE_ATTRIBUTE , type)
157+ val drawable = buildPlaceholderDrawable(adapter, attrs)
158+ val span = AztecPlaceholderSpan (aztecText.context, drawable, 0 , attrs,
159+ this , aztecText, WeakReference (adapter), TAG = htmlTag)
160+ aztecText.replaceMediaSpan(span) { attributes ->
161+ attributes.getValue(UUID_ATTRIBUTE ) == uuid
162+ }
163+ insertContentOverSpanWithId(uuid)
164+ }
165+
166+ /* *
167+ * Use this function to either update or remove an item. The decision whether to remove or update will be made
168+ * based upon the results of the parameter functions. An example of usage is a gallery of images. If the user wants
169+ * to remove one image in the gallery, they would call this method. If the removed image is one of many, they might
170+ * want to update the current parameters instead of removing the entire gallery. However, if the removed image is
171+ * the last one in the gallery, they will probably want to remove the entire gallery.
172+ * @param uuid UUID of the span we want to remove or update
173+ * @param shouldUpdateItem This function should return true if the span can be updated, false if it should be removed
174+ * @param updateItem Function that updates the selected item
175+ */
176+ suspend fun removeOrUpdate (uuid : String , shouldUpdateItem : (Attributes ) -> Boolean , updateItem : (currentAttributes: Map <String , String >) -> Map <String , String >): Boolean {
177+ val currentItem = aztecText.editableText.getSpans(0 , aztecText.length(), AztecPlaceholderSpan ::class .java).find {
178+ it.attributes.getValue(UUID_ATTRIBUTE ) == uuid
179+ } ? : return false
180+ if (shouldUpdateItem(currentItem.attributes)) {
181+ val type = currentItem.attributes.getValue(TYPE_ATTRIBUTE )
182+ val selectionStart = aztecText.selectionStart
183+ val selectionEnd = aztecText.selectionEnd
184+ aztecText.setSelection(aztecText.editableText.getSpanStart(currentItem))
185+ updateSpan(type, currentItem, updateItem = { attributes, _, _ ->
186+ updateItem(attributes)
187+ }, placeAtStart = false , currentType = type)
188+ aztecText.setSelection(selectionStart, selectionEnd)
189+ } else {
190+ removeItem(uuid)
191+ }
192+ return true
193+ }
194+
156195 private data class TargetItem (val span : AztecPlaceholderSpan , val placeAtStart : Boolean )
157196
158197 private fun getTargetItem (): TargetItem ? {
@@ -189,13 +228,21 @@ class PlaceholderManager(
189228 }
190229
191230 /* *
192- * Call this method to remove a placeholder from both the AztecText and the overlaying layer programatically .
231+ * Call this method to remove a placeholder from both the AztecText and the overlaying layer programmatically .
193232 * @param predicate determines whether a span should be removed
194233 */
195234 fun removeItem (predicate : (Attributes ) -> Boolean ) {
196235 aztecText.removeMedia { predicate(it) }
197236 }
198237
238+ /* *
239+ * Call this method to remove a placeholder from both the AztecText and the overlaying layer programmatically.
240+ * @param uuid of the removed item
241+ */
242+ fun removeItem (uuid : String ) {
243+ aztecText.removeMedia { it.getValue(UUID_ATTRIBUTE ) == uuid }
244+ }
245+
199246 private suspend fun buildPlaceholderDrawable (adapter : PlaceholderAdapter , attrs : AztecAttributes ): Drawable {
200247 val drawable = ContextCompat .getDrawable(aztecText.context, android.R .color.transparent)!!
201248 val editorWidth = if (aztecText.width > 0 ) {
0 commit comments